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

Conflicts:
	drivers/net/wireless/iwlwifi/pcie/tx.c
This commit is contained in:
John W. Linville 2012-11-28 10:56:03 -05:00
commit 79d38f7d6c
289 changed files with 27540 additions and 8408 deletions

View File

@ -5157,6 +5157,7 @@ F: net/nfc/
F: include/linux/nfc.h
F: include/net/nfc/
F: drivers/nfc/
F: include/linux/platform_data/pn544.h
NFS, SUNRPC, AND LOCKD CLIENTS
M: Trond Myklebust <Trond.Myklebust@netapp.com>

View File

@ -96,6 +96,7 @@ static struct usb_device_id btusb_table[] = {
{ USB_DEVICE(0x0c10, 0x0000) },
/* Broadcom BCM20702A0 */
{ USB_DEVICE(0x0b05, 0x17b5) },
{ USB_DEVICE(0x04ca, 0x2003) },
{ USB_DEVICE(0x0489, 0xe042) },
{ USB_DEVICE(0x413c, 0x8197) },

View File

@ -379,7 +379,7 @@ static int at76_usbdfu_download(struct usb_device *udev, u8 *buf, u32 size,
manifest_sync_timeout);
if (!size) {
dev_printk(KERN_ERR, &udev->dev, "FW buffer length invalid!\n");
dev_err(&udev->dev, "FW buffer length invalid!\n");
return -EINVAL;
}
@ -391,8 +391,8 @@ static int at76_usbdfu_download(struct usb_device *udev, u8 *buf, u32 size,
if (need_dfu_state) {
ret = at76_dfu_get_state(udev, &dfu_state);
if (ret < 0) {
dev_printk(KERN_ERR, &udev->dev,
"cannot get DFU state: %d\n", ret);
dev_err(&udev->dev,
"cannot get DFU state: %d\n", ret);
goto exit;
}
need_dfu_state = 0;
@ -407,9 +407,9 @@ static int at76_usbdfu_download(struct usb_device *udev, u8 *buf, u32 size,
dfu_timeout = at76_get_timeout(&dfu_stat_buf);
need_dfu_state = 0;
} else
dev_printk(KERN_ERR, &udev->dev,
"at76_dfu_get_status returned %d\n",
ret);
dev_err(&udev->dev,
"at76_dfu_get_status returned %d\n",
ret);
break;
case STATE_DFU_DOWNLOAD_BUSY:
@ -438,9 +438,9 @@ static int at76_usbdfu_download(struct usb_device *udev, u8 *buf, u32 size,
blockno++;
if (ret != bsize)
dev_printk(KERN_ERR, &udev->dev,
"at76_load_int_fw_block "
"returned %d\n", ret);
dev_err(&udev->dev,
"at76_load_int_fw_block returned %d\n",
ret);
need_dfu_state = 1;
break;
@ -1255,8 +1255,7 @@ static int at76_load_external_fw(struct usb_device *udev, struct fwentry *fwe)
at76_dbg(DBG_DEVSTART, "opmode %d", op_mode);
if (op_mode != OPMODE_NORMAL_NIC_WITHOUT_FLASH) {
dev_printk(KERN_ERR, &udev->dev, "unexpected opmode %d\n",
op_mode);
dev_err(&udev->dev, "unexpected opmode %d\n", op_mode);
return -EINVAL;
}
@ -1275,9 +1274,9 @@ static int at76_load_external_fw(struct usb_device *udev, struct fwentry *fwe)
size, bsize, blockno);
ret = at76_load_ext_fw_block(udev, blockno, block, bsize);
if (ret != bsize) {
dev_printk(KERN_ERR, &udev->dev,
"loading %dth firmware block failed: %d\n",
blockno, ret);
dev_err(&udev->dev,
"loading %dth firmware block failed: %d\n",
blockno, ret);
goto exit;
}
buf += bsize;
@ -1293,8 +1292,8 @@ static int at76_load_external_fw(struct usb_device *udev, struct fwentry *fwe)
exit:
kfree(block);
if (ret < 0)
dev_printk(KERN_ERR, &udev->dev,
"downloading external firmware failed: %d\n", ret);
dev_err(&udev->dev,
"downloading external firmware failed: %d\n", ret);
return ret;
}
@ -1308,8 +1307,8 @@ static int at76_load_internal_fw(struct usb_device *udev, struct fwentry *fwe)
need_remap ? 0 : 2 * HZ);
if (ret < 0) {
dev_printk(KERN_ERR, &udev->dev,
"downloading internal fw failed with %d\n", ret);
dev_err(&udev->dev,
"downloading internal fw failed with %d\n", ret);
goto exit;
}
@ -1319,8 +1318,8 @@ static int at76_load_internal_fw(struct usb_device *udev, struct fwentry *fwe)
if (need_remap) {
ret = at76_remap(udev);
if (ret < 0) {
dev_printk(KERN_ERR, &udev->dev,
"sending REMAP failed with %d\n", ret);
dev_err(&udev->dev,
"sending REMAP failed with %d\n", ret);
goto exit;
}
}
@ -1555,11 +1554,10 @@ static struct fwentry *at76_load_firmware(struct usb_device *udev,
at76_dbg(DBG_FW, "downloading firmware %s", fwe->fwname);
ret = request_firmware(&fwe->fw, fwe->fwname, &udev->dev);
if (ret < 0) {
dev_printk(KERN_ERR, &udev->dev, "firmware %s not found!\n",
fwe->fwname);
dev_printk(KERN_ERR, &udev->dev,
"you may need to download the firmware from "
"http://developer.berlios.de/projects/at76c503a/\n");
dev_err(&udev->dev, "firmware %s not found!\n",
fwe->fwname);
dev_err(&udev->dev,
"you may need to download the firmware from http://developer.berlios.de/projects/at76c503a/\n");
goto exit;
}
@ -1567,17 +1565,17 @@ static struct fwentry *at76_load_firmware(struct usb_device *udev,
fwh = (struct at76_fw_header *)(fwe->fw->data);
if (fwe->fw->size <= sizeof(*fwh)) {
dev_printk(KERN_ERR, &udev->dev,
"firmware is too short (0x%zx)\n", fwe->fw->size);
dev_err(&udev->dev,
"firmware is too short (0x%zx)\n", fwe->fw->size);
goto exit;
}
/* CRC currently not checked */
fwe->board_type = le32_to_cpu(fwh->board_type);
if (fwe->board_type != board_type) {
dev_printk(KERN_ERR, &udev->dev,
"board type mismatch, requested %u, got %u\n",
board_type, fwe->board_type);
dev_err(&udev->dev,
"board type mismatch, requested %u, got %u\n",
board_type, fwe->board_type);
goto exit;
}
@ -2150,8 +2148,7 @@ static int at76_alloc_urbs(struct at76_priv *priv,
}
if (!ep_in || !ep_out) {
dev_printk(KERN_ERR, &interface->dev,
"bulk endpoints missing\n");
dev_err(&interface->dev, "bulk endpoints missing\n");
return -ENXIO;
}
@ -2161,15 +2158,14 @@ static int at76_alloc_urbs(struct at76_priv *priv,
priv->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
priv->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!priv->rx_urb || !priv->tx_urb) {
dev_printk(KERN_ERR, &interface->dev, "cannot allocate URB\n");
dev_err(&interface->dev, "cannot allocate URB\n");
return -ENOMEM;
}
buffer_size = sizeof(struct at76_tx_buffer) + MAX_PADDING_SIZE;
priv->bulk_out_buffer = kmalloc(buffer_size, GFP_KERNEL);
if (!priv->bulk_out_buffer) {
dev_printk(KERN_ERR, &interface->dev,
"cannot allocate output buffer\n");
dev_err(&interface->dev, "cannot allocate output buffer\n");
return -ENOMEM;
}
@ -2230,8 +2226,7 @@ static int at76_init_new_device(struct at76_priv *priv,
/* MAC address */
ret = at76_get_hw_config(priv);
if (ret < 0) {
dev_printk(KERN_ERR, &interface->dev,
"cannot get MAC address\n");
dev_err(&interface->dev, "cannot get MAC address\n");
goto exit;
}
@ -2358,8 +2353,8 @@ static int at76_probe(struct usb_interface *interface,
we get 204 with 2.4.23, Fiberline FL-WL240u (505A+RFMD2958) ??? */
if (op_mode == OPMODE_HW_CONFIG_MODE) {
dev_printk(KERN_ERR, &interface->dev,
"cannot handle a device in HW_CONFIG_MODE\n");
dev_err(&interface->dev,
"cannot handle a device in HW_CONFIG_MODE\n");
ret = -EBUSY;
goto error;
}
@ -2371,9 +2366,9 @@ static int at76_probe(struct usb_interface *interface,
"downloading internal firmware\n");
ret = at76_load_internal_fw(udev, fwe);
if (ret < 0) {
dev_printk(KERN_ERR, &interface->dev,
"error %d downloading internal firmware\n",
ret);
dev_err(&interface->dev,
"error %d downloading internal firmware\n",
ret);
goto error;
}
usb_put_dev(udev);
@ -2408,8 +2403,8 @@ static int at76_probe(struct usb_interface *interface,
/* Re-check firmware version */
ret = at76_get_mib(udev, MIB_FW_VERSION, &fwv, sizeof(fwv));
if (ret < 0) {
dev_printk(KERN_ERR, &interface->dev,
"error %d getting firmware version\n", ret);
dev_err(&interface->dev,
"error %d getting firmware version\n", ret);
goto error;
}
}
@ -2449,7 +2444,7 @@ static void at76_disconnect(struct usb_interface *interface)
wiphy_info(priv->hw->wiphy, "disconnecting\n");
at76_delete_device(priv);
dev_printk(KERN_INFO, &interface->dev, "disconnected\n");
dev_info(&interface->dev, "disconnected\n");
}
/* Structure for registering this driver with the USB subsystem */

View File

@ -50,18 +50,19 @@ static void ar5523_read_reply(struct ar5523 *ar, struct ar5523_cmd_hdr *hdr,
struct ar5523_tx_cmd *cmd)
{
int dlen, olen;
u32 *rp;
__be32 *rp;
dlen = hdr->len - sizeof(*hdr);
dlen = be32_to_cpu(hdr->len) - sizeof(*hdr);
if (dlen < 0) {
WARN_ON(1);
goto out;
}
ar5523_dbg(ar, "Code = %d len = %d\n", hdr->code & 0xff, dlen);
ar5523_dbg(ar, "Code = %d len = %d\n", be32_to_cpu(hdr->code) & 0xff,
dlen);
rp = (u32 *)(hdr + 1);
rp = (__be32 *)(hdr + 1);
if (dlen >= sizeof(u32)) {
olen = be32_to_cpu(rp[0]);
dlen -= sizeof(u32);
@ -95,6 +96,7 @@ static void ar5523_cmd_rx_cb(struct urb *urb)
struct ar5523_tx_cmd *cmd = &ar->tx_cmd;
struct ar5523_cmd_hdr *hdr = ar->rx_cmd_buf;
int dlen;
u32 code, hdrlen;
if (urb->status) {
if (urb->status != -ESHUTDOWN)
@ -110,15 +112,15 @@ static void ar5523_cmd_rx_cb(struct urb *urb)
ar5523_dbg(ar, "%s code %02x priv %d\n", __func__,
be32_to_cpu(hdr->code) & 0xff, hdr->priv);
hdr->code = be32_to_cpu(hdr->code);
hdr->len = be32_to_cpu(hdr->len);
code = be32_to_cpu(hdr->code);
hdrlen = be32_to_cpu(hdr->len);
switch (hdr->code & 0xff) {
switch (code & 0xff) {
default:
/* reply to a read command */
if (hdr->priv != AR5523_CMD_ID) {
ar5523_err(ar, "Unexpected command id: %02x\n",
hdr->code & 0xff);
code & 0xff);
goto skip;
}
ar5523_read_reply(ar, hdr, cmd);
@ -147,7 +149,7 @@ static void ar5523_cmd_rx_cb(struct urb *urb)
case WDCMSG_TARGET_START:
/* This command returns a bogus id so it needs special
handling */
dlen = hdr->len - sizeof(*hdr);
dlen = hdrlen - sizeof(*hdr);
if (dlen != (int)sizeof(u32)) {
ar5523_err(ar, "Invalid reply to WDCMSG_TARGET_START");
return;
@ -303,7 +305,7 @@ static int ar5523_config(struct ar5523 *ar, u32 reg, u32 val)
write.reg = cpu_to_be32(reg);
write.len = cpu_to_be32(0); /* 0 = single write */
*(u32 *)write.data = cpu_to_be32(val);
*(__be32 *)write.data = cpu_to_be32(val);
error = ar5523_cmd_write(ar, WDCMSG_TARGET_SET_CONFIG, &write,
3 * sizeof(u32), 0);
@ -335,29 +337,30 @@ static int ar5523_get_status(struct ar5523 *ar, u32 which, void *odata,
int olen)
{
int error;
__be32 which_be;
which = cpu_to_be32(which);
which_be = cpu_to_be32(which);
error = ar5523_cmd_read(ar, WDCMSG_TARGET_GET_STATUS,
&which, sizeof(which), odata, olen, AR5523_CMD_FLAG_MAGIC);
&which_be, sizeof(which_be), odata, olen, AR5523_CMD_FLAG_MAGIC);
if (error != 0)
ar5523_err(ar, "could not read EEPROM offset 0x%02x\n",
be32_to_cpu(which));
ar5523_err(ar, "could not read EEPROM offset 0x%02x\n", which);
return error;
}
static int ar5523_get_capability(struct ar5523 *ar, u32 cap, u32 *val)
{
int error;
__be32 cap_be, val_be;
cap = cpu_to_be32(cap);
error = ar5523_cmd_read(ar, WDCMSG_TARGET_GET_CAPABILITY,
&cap, sizeof(cap), val, sizeof(u32), AR5523_CMD_FLAG_MAGIC);
cap_be = cpu_to_be32(cap);
error = ar5523_cmd_read(ar, WDCMSG_TARGET_GET_CAPABILITY, &cap_be,
sizeof(cap_be), &val_be, sizeof(__be32),
AR5523_CMD_FLAG_MAGIC);
if (error != 0) {
ar5523_err(ar, "could not read capability %u\n",
be32_to_cpu(cap));
ar5523_err(ar, "could not read capability %u\n", cap);
return error;
}
*val = be32_to_cpu(*val);
*val = be32_to_cpu(val_be);
return error;
}
@ -1193,8 +1196,8 @@ static void ar5523_create_rateset(struct ar5523 *ar,
if (!sta) {
ar5523_info(ar, "STA not found. Cannot set rates\n");
sta_rate_set = bss_conf->basic_rates;
}
sta_rate_set = sta->supp_rates[ar->hw->conf.channel->band];
} else
sta_rate_set = sta->supp_rates[ar->hw->conf.channel->band];
ar5523_dbg(ar, "sta rate_set = %08x\n", sta_rate_set);
@ -1789,18 +1792,7 @@ static struct usb_driver ar5523_driver = {
.disconnect = ar5523_disconnect,
};
static int __init ar5523_init(void)
{
return usb_register(&ar5523_driver);
}
static void __exit ar5523_exit(void)
{
usb_deregister(&ar5523_driver);
}
module_usb_driver(ar5523_driver);
MODULE_LICENSE("Dual BSD/GPL");
MODULE_FIRMWARE(AR5523_FIRMWARE_FILE);
module_init(ar5523_init);
module_exit(ar5523_exit);

View File

@ -161,7 +161,7 @@ struct ar5523_rx_desc {
struct ar5523_tx_desc {
__be32 msglen;
__be32 msgid; /* msg id (supplied by host) */
u32 msgid; /* msg id (supplied by host) */
__be32 type; /* opcode: WDMSG_SEND or WDCMSG_FLUSH */
__be32 txqid; /* tx queue id and flags */
#define UATH_TXQID_MASK 0x0f

View File

@ -236,17 +236,4 @@ static struct platform_driver ath_ahb_driver = {
},
};
static int __init
ath5k_ahb_init(void)
{
return platform_driver_register(&ath_ahb_driver);
}
static void __exit
ath5k_ahb_exit(void)
{
platform_driver_unregister(&ath_ahb_driver);
}
module_init(ath5k_ahb_init);
module_exit(ath5k_ahb_exit);
module_platform_driver(ath_ahb_driver);

View File

@ -511,8 +511,9 @@ ath5k_update_bssid_mask_and_opmode(struct ath5k_hw *ah,
ath5k_vif_iter(&iter_data, vif->addr, vif);
/* Get list of all active MAC addresses */
ieee80211_iterate_active_interfaces_atomic(ah->hw, ath5k_vif_iter,
&iter_data);
ieee80211_iterate_active_interfaces_atomic(
ah->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
ath5k_vif_iter, &iter_data);
memcpy(ah->bssidmask, iter_data.mask, ETH_ALEN);
ah->opmode = iter_data.opmode;
@ -1348,7 +1349,7 @@ ath5k_receive_frame(struct ath5k_hw *ah, struct sk_buff *skb,
* right now, so it's not too bad...
*/
rxs->mactime = ath5k_extend_tsf(ah, rs->rs_tstamp);
rxs->flag |= RX_FLAG_MACTIME_MPDU;
rxs->flag |= RX_FLAG_MACTIME_START;
rxs->freq = ah->curchan->center_freq;
rxs->band = ah->curchan->band;
@ -3045,8 +3046,9 @@ ath5k_any_vif_assoc(struct ath5k_hw *ah)
iter_data.need_set_hw_addr = false;
iter_data.found_active = true;
ieee80211_iterate_active_interfaces_atomic(ah->hw, ath5k_vif_iter,
&iter_data);
ieee80211_iterate_active_interfaces_atomic(
ah->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
ath5k_vif_iter, &iter_data);
return iter_data.any_assoc;
}

View File

@ -452,8 +452,9 @@ ath5k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
iter_data.hw_macaddr = NULL;
iter_data.n_stas = 0;
iter_data.need_set_hw_addr = false;
ieee80211_iterate_active_interfaces_atomic(ah->hw, ath5k_vif_iter,
&iter_data);
ieee80211_iterate_active_interfaces_atomic(
ah->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
ath5k_vif_iter, &iter_data);
/* Set up RX Filter */
if (iter_data.n_stas > 1) {

View File

@ -789,9 +789,9 @@ ath5k_hw_nic_wakeup(struct ath5k_hw *ah, struct ieee80211_channel *channel)
* (I don't think it supports 44MHz) */
/* On 2425 initvals TURBO_SHORT is not present */
if (ah->ah_bwmode == AR5K_BWMODE_40MHZ) {
turbo = AR5K_PHY_TURBO_MODE |
(ah->ah_radio == AR5K_RF2425) ? 0 :
AR5K_PHY_TURBO_SHORT;
turbo = AR5K_PHY_TURBO_MODE;
if (ah->ah_radio != AR5K_RF2425)
turbo |= AR5K_PHY_TURBO_SHORT;
} else if (ah->ah_bwmode != AR5K_BWMODE_DEFAULT) {
if (ah->ah_radio == AR5K_RF5413) {
mode |= (ah->ah_bwmode == AR5K_BWMODE_10MHZ) ?

View File

@ -30,3 +30,12 @@ config ATH6KL_DEBUG
depends on ATH6KL
---help---
Enables debug support
config ATH6KL_REGDOMAIN
bool "Atheros ath6kl regdomain support"
depends on ATH6KL
depends on CFG80211_CERTIFICATION_ONUS
---help---
Enabling this makes it possible to change the regdomain in
the firmware. This can be only enabled if regulatory requirements
are taken into account.

View File

@ -34,6 +34,7 @@ ath6kl_core-y += main.o
ath6kl_core-y += txrx.o
ath6kl_core-y += wmi.o
ath6kl_core-y += core.o
ath6kl_core-y += recovery.o
ath6kl_core-$(CONFIG_NL80211_TESTMODE) += testmode.o
obj-$(CONFIG_ATH6KL_SDIO) += ath6kl_sdio.o

View File

@ -147,15 +147,15 @@ static bool __ath6kl_cfg80211_sscan_stop(struct ath6kl_vif *vif)
{
struct ath6kl *ar = vif->ar;
if (ar->state != ATH6KL_STATE_SCHED_SCAN)
if (!test_and_clear_bit(SCHED_SCANNING, &vif->flags))
return false;
del_timer_sync(&vif->sched_scan_timer);
ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
ATH6KL_HOST_MODE_AWAKE);
if (ar->state == ATH6KL_STATE_RECOVERY)
return true;
ar->state = ATH6KL_STATE_ON;
ath6kl_wmi_enable_sched_scan_cmd(ar->wmi, vif->fw_vif_idx, false);
return true;
}
@ -369,17 +369,13 @@ static int ath6kl_nliftype_to_drv_iftype(enum nl80211_iftype type, u8 *nw_type)
{
switch (type) {
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_P2P_CLIENT:
*nw_type = INFRA_NETWORK;
break;
case NL80211_IFTYPE_ADHOC:
*nw_type = ADHOC_NETWORK;
break;
case NL80211_IFTYPE_AP:
*nw_type = AP_NETWORK;
break;
case NL80211_IFTYPE_P2P_CLIENT:
*nw_type = INFRA_NETWORK;
break;
case NL80211_IFTYPE_P2P_GO:
*nw_type = AP_NETWORK;
break;
@ -1031,30 +1027,15 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy,
vif->scan_req = request;
if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX,
ar->fw_capabilities)) {
/*
* If capable of doing P2P mgmt operations using
* station interface, send additional information like
* supported rates to advertise and xmit rates for
* probe requests
*/
ret = ath6kl_wmi_beginscan_cmd(ar->wmi, vif->fw_vif_idx,
WMI_LONG_SCAN, force_fg_scan,
false, 0,
ATH6KL_FG_SCAN_INTERVAL,
n_channels, channels,
request->no_cck,
request->rates);
} else {
ret = ath6kl_wmi_startscan_cmd(ar->wmi, vif->fw_vif_idx,
WMI_LONG_SCAN, force_fg_scan,
false, 0,
ATH6KL_FG_SCAN_INTERVAL,
n_channels, channels);
}
ret = ath6kl_wmi_beginscan_cmd(ar->wmi, vif->fw_vif_idx,
WMI_LONG_SCAN, force_fg_scan,
false, 0,
ATH6KL_FG_SCAN_INTERVAL,
n_channels, channels,
request->no_cck,
request->rates);
if (ret) {
ath6kl_err("wmi_startscan_cmd failed\n");
ath6kl_err("failed to start scan: %d\n", ret);
vif->scan_req = NULL;
}
@ -1093,15 +1074,18 @@ out:
void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq,
enum wmi_phy_mode mode)
{
enum nl80211_channel_type type;
struct cfg80211_chan_def chandef;
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
"channel switch notify nw_type %d freq %d mode %d\n",
vif->nw_type, freq, mode);
type = (mode == WMI_11G_HT20) ? NL80211_CHAN_HT20 : NL80211_CHAN_NO_HT;
cfg80211_chandef_create(&chandef,
ieee80211_get_channel(vif->ar->wiphy, freq),
(mode == WMI_11G_HT20) ?
NL80211_CHAN_HT20 : NL80211_CHAN_NO_HT);
cfg80211_ch_switch_notify(vif->ndev, freq, type);
cfg80211_ch_switch_notify(vif->ndev, &chandef);
}
static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
@ -1384,11 +1368,8 @@ static int ath6kl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
return 0;
}
/*
* The type nl80211_tx_power_setting replaces the following
* data type from 2.6.36 onwards
*/
static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
struct wireless_dev *wdev,
enum nl80211_tx_power_setting type,
int mbm)
{
@ -1423,7 +1404,9 @@ static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
return 0;
}
static int ath6kl_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm)
static int ath6kl_cfg80211_get_txpower(struct wiphy *wiphy,
struct wireless_dev *wdev,
int *dbm)
{
struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
struct ath6kl_vif *vif;
@ -1614,8 +1597,8 @@ static int ath6kl_cfg80211_join_ibss(struct wiphy *wiphy,
vif->ssid_len = ibss_param->ssid_len;
memcpy(vif->ssid, ibss_param->ssid, vif->ssid_len);
if (ibss_param->channel)
vif->ch_hint = ibss_param->channel->center_freq;
if (ibss_param->chandef.chan)
vif->ch_hint = ibss_param->chandef.chan->center_freq;
if (ibss_param->channel_fixed) {
/*
@ -1889,7 +1872,7 @@ static int ath6kl_wow_usr(struct ath6kl *ar, struct ath6kl_vif *vif,
struct cfg80211_wowlan *wow, u32 *filter)
{
int ret, pos;
u8 mask[WOW_MASK_SIZE];
u8 mask[WOW_PATTERN_SIZE];
u16 i;
/* Configure the patterns that we received from the user. */
@ -2107,33 +2090,16 @@ static int ath6kl_cfg80211_host_sleep(struct ath6kl *ar, struct ath6kl_vif *vif)
return ret;
}
static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
static int ath6kl_wow_suspend_vif(struct ath6kl_vif *vif,
struct cfg80211_wowlan *wow, u32 *filter)
{
struct ath6kl *ar = vif->ar;
struct in_device *in_dev;
struct in_ifaddr *ifa;
struct ath6kl_vif *vif;
int ret;
u32 filter = 0;
u16 i, bmiss_time;
u8 index = 0;
__be32 ips[MAX_IP_ADDRS];
/* The FW currently can't support multi-vif WoW properly. */
if (ar->num_vif > 1)
return -EIO;
vif = ath6kl_vif_first(ar);
if (!vif)
return -EIO;
if (!ath6kl_cfg80211_ready(vif))
return -EIO;
if (!test_bit(CONNECTED, &vif->flags))
return -ENOTCONN;
if (wow && (wow->n_patterns > WOW_MAX_FILTERS_PER_LIST))
return -EINVAL;
u8 index = 0;
if (!test_bit(NETDEV_MCAST_ALL_ON, &vif->flags) &&
test_bit(ATH6KL_FW_CAPABILITY_WOW_MULTICAST_FILTER,
@ -2155,7 +2121,7 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
* the user.
*/
if (wow)
ret = ath6kl_wow_usr(ar, vif, wow, &filter);
ret = ath6kl_wow_usr(ar, vif, wow, filter);
else if (vif->nw_type == AP_NETWORK)
ret = ath6kl_wow_ap(ar, vif);
else
@ -2190,12 +2156,10 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
return ret;
}
ar->state = ATH6KL_STATE_SUSPENDING;
/* Setup own IP addr for ARP agent. */
in_dev = __in_dev_get_rtnl(vif->ndev);
if (!in_dev)
goto skip_arp;
return 0;
ifa = in_dev->ifa_list;
memset(&ips, 0, sizeof(ips));
@ -2218,41 +2182,61 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
return ret;
}
skip_arp:
ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx,
return ret;
}
static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
{
struct ath6kl_vif *first_vif, *vif;
int ret = 0;
u32 filter = 0;
bool connected = false;
/* enter / leave wow suspend on first vif always */
first_vif = ath6kl_vif_first(ar);
if (WARN_ON(unlikely(!first_vif)) ||
!ath6kl_cfg80211_ready(first_vif))
return -EIO;
if (wow && (wow->n_patterns > WOW_MAX_FILTERS_PER_LIST))
return -EINVAL;
/* install filters for each connected vif */
spin_lock_bh(&ar->list_lock);
list_for_each_entry(vif, &ar->vif_list, list) {
if (!test_bit(CONNECTED, &vif->flags) ||
!ath6kl_cfg80211_ready(vif))
continue;
connected = true;
ret = ath6kl_wow_suspend_vif(vif, wow, &filter);
if (ret)
break;
}
spin_unlock_bh(&ar->list_lock);
if (!connected)
return -ENOTCONN;
else if (ret)
return ret;
ar->state = ATH6KL_STATE_SUSPENDING;
ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, first_vif->fw_vif_idx,
ATH6KL_WOW_MODE_ENABLE,
filter,
WOW_HOST_REQ_DELAY);
if (ret)
return ret;
ret = ath6kl_cfg80211_host_sleep(ar, vif);
if (ret)
return ret;
return 0;
return ath6kl_cfg80211_host_sleep(ar, first_vif);
}
static int ath6kl_wow_resume(struct ath6kl *ar)
static int ath6kl_wow_resume_vif(struct ath6kl_vif *vif)
{
struct ath6kl_vif *vif;
struct ath6kl *ar = vif->ar;
int ret;
vif = ath6kl_vif_first(ar);
if (!vif)
return -EIO;
ar->state = ATH6KL_STATE_RESUMING;
ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
ATH6KL_HOST_MODE_AWAKE);
if (ret) {
ath6kl_warn("Failed to configure host sleep mode for wow resume: %d\n",
ret);
ar->state = ATH6KL_STATE_WOW;
return ret;
}
if (vif->nw_type != AP_NETWORK) {
ret = ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx,
0, 0, 0, 0, 0, 0, 3, 0, 0, 0);
@ -2270,13 +2254,11 @@ static int ath6kl_wow_resume(struct ath6kl *ar)
return ret;
}
ar->state = ATH6KL_STATE_ON;
if (!test_bit(NETDEV_MCAST_ALL_OFF, &vif->flags) &&
test_bit(ATH6KL_FW_CAPABILITY_WOW_MULTICAST_FILTER,
ar->fw_capabilities)) {
ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi,
vif->fw_vif_idx, true);
vif->fw_vif_idx, true);
if (ret)
return ret;
}
@ -2286,6 +2268,48 @@ static int ath6kl_wow_resume(struct ath6kl *ar)
return 0;
}
static int ath6kl_wow_resume(struct ath6kl *ar)
{
struct ath6kl_vif *vif;
int ret;
vif = ath6kl_vif_first(ar);
if (WARN_ON(unlikely(!vif)) ||
!ath6kl_cfg80211_ready(vif))
return -EIO;
ar->state = ATH6KL_STATE_RESUMING;
ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
ATH6KL_HOST_MODE_AWAKE);
if (ret) {
ath6kl_warn("Failed to configure host sleep mode for wow resume: %d\n",
ret);
goto cleanup;
}
spin_lock_bh(&ar->list_lock);
list_for_each_entry(vif, &ar->vif_list, list) {
if (!test_bit(CONNECTED, &vif->flags) ||
!ath6kl_cfg80211_ready(vif))
continue;
ret = ath6kl_wow_resume_vif(vif);
if (ret)
break;
}
spin_unlock_bh(&ar->list_lock);
if (ret)
goto cleanup;
ar->state = ATH6KL_STATE_ON;
return 0;
cleanup:
ar->state = ATH6KL_STATE_WOW;
return ret;
}
static int ath6kl_cfg80211_deepsleep_suspend(struct ath6kl *ar)
{
struct ath6kl_vif *vif;
@ -2422,13 +2446,6 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar,
break;
case ATH6KL_CFG_SUSPEND_SCHED_SCAN:
/*
* Nothing needed for schedule scan, firmware is already in
* wow mode and sleeping most of the time.
*/
break;
default:
break;
}
@ -2476,9 +2493,6 @@ int ath6kl_cfg80211_resume(struct ath6kl *ar)
}
break;
case ATH6KL_STATE_SCHED_SCAN:
break;
default:
break;
}
@ -2495,14 +2509,23 @@ static int __ath6kl_cfg80211_suspend(struct wiphy *wiphy,
{
struct ath6kl *ar = wiphy_priv(wiphy);
ath6kl_recovery_suspend(ar);
return ath6kl_hif_suspend(ar, wow);
}
static int __ath6kl_cfg80211_resume(struct wiphy *wiphy)
{
struct ath6kl *ar = wiphy_priv(wiphy);
int err;
return ath6kl_hif_resume(ar);
err = ath6kl_hif_resume(ar);
if (err)
return err;
ath6kl_recovery_resume(ar);
return 0;
}
/*
@ -2739,6 +2762,7 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
int res;
int i, ret;
u16 rsn_capab = 0;
int inactivity_timeout = 0;
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s:\n", __func__);
@ -2857,7 +2881,7 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
p.ssid_len = vif->ssid_len;
memcpy(p.ssid, vif->ssid, vif->ssid_len);
p.dot11_auth_mode = vif->dot11_auth_mode;
p.ch = cpu_to_le16(info->channel->center_freq);
p.ch = cpu_to_le16(info->chandef.chan->center_freq);
/* Enable uAPSD support by default */
res = ath6kl_wmi_ap_set_apsd(ar->wmi, vif->fw_vif_idx, true);
@ -2875,14 +2899,22 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
}
if (info->inactivity_timeout) {
inactivity_timeout = info->inactivity_timeout;
if (ar->hw.flags & ATH6KL_HW_AP_INACTIVITY_MINS)
inactivity_timeout = DIV_ROUND_UP(inactivity_timeout,
60);
res = ath6kl_wmi_set_inact_period(ar->wmi, vif->fw_vif_idx,
info->inactivity_timeout);
inactivity_timeout);
if (res < 0)
return res;
}
if (ath6kl_set_htcap(vif, info->channel->band,
info->channel_type != NL80211_CHAN_NO_HT))
if (ath6kl_set_htcap(vif, info->chandef.chan->band,
cfg80211_get_chandef_type(&info->chandef)
!= NL80211_CHAN_NO_HT))
return -EIO;
/*
@ -2898,6 +2930,7 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
WLAN_EID_RSN, WMI_RSN_IE_CAPB,
(const u8 *) &rsn_capab,
sizeof(rsn_capab));
vif->rsn_capab = rsn_capab;
if (res < 0)
return res;
}
@ -2977,7 +3010,6 @@ static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev,
static int ath6kl_remain_on_channel(struct wiphy *wiphy,
struct wireless_dev *wdev,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type,
unsigned int duration,
u64 *cookie)
{
@ -3136,10 +3168,8 @@ static bool ath6kl_is_p2p_go_ssid(const u8 *buf, size_t len)
static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
struct ieee80211_channel *chan, bool offchan,
enum nl80211_channel_type channel_type,
bool channel_type_valid, unsigned int wait,
const u8 *buf, size_t len, bool no_cck,
bool dont_wait_for_ack, u64 *cookie)
unsigned int wait, const u8 *buf, size_t len,
bool no_cck, bool dont_wait_for_ack, u64 *cookie)
{
struct ath6kl_vif *vif = ath6kl_vif_from_wdev(wdev);
struct ath6kl *ar = ath6kl_priv(vif->ndev);
@ -3211,7 +3241,7 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
struct ath6kl *ar = ath6kl_priv(dev);
struct ath6kl_vif *vif = netdev_priv(dev);
u16 interval;
int ret;
int ret, rssi_thold;
if (ar->state != ATH6KL_STATE_ON)
return -EIO;
@ -3219,10 +3249,6 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
if (vif->sme_state != SME_DISCONNECTED)
return -EBUSY;
/* The FW currently can't support multi-vif WoW properly. */
if (ar->num_vif > 1)
return -EIO;
ath6kl_cfg80211_scan_complete_event(vif, true);
ret = ath6kl_set_probed_ssids(ar, vif, request->ssids,
@ -3244,6 +3270,23 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
return ret;
}
if (test_bit(ATH6KL_FW_CAPABILITY_RSSI_SCAN_THOLD,
ar->fw_capabilities)) {
if (request->rssi_thold <= NL80211_SCAN_RSSI_THOLD_OFF)
rssi_thold = 0;
else if (request->rssi_thold < -127)
rssi_thold = -127;
else
rssi_thold = request->rssi_thold;
ret = ath6kl_wmi_set_rssi_filter_cmd(ar->wmi, vif->fw_vif_idx,
rssi_thold);
if (ret) {
ath6kl_err("failed to set RSSI threshold for scan\n");
return ret;
}
}
/* fw uses seconds, also make sure that it's >0 */
interval = max_t(u16, 1, request->interval / 1000);
@ -3251,15 +3294,6 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
interval, interval,
vif->bg_scan_period, 0, 0, 0, 3, 0, 0, 0);
ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx,
ATH6KL_WOW_MODE_ENABLE,
WOW_FILTER_SSID,
WOW_HOST_REQ_DELAY);
if (ret) {
ath6kl_warn("Failed to enable wow with ssid filter: %d\n", ret);
return ret;
}
/* this also clears IE in fw if it's not set */
ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
WMI_FRAME_PROBE_REQ,
@ -3270,17 +3304,13 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
return ret;
}
ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
ATH6KL_HOST_MODE_ASLEEP);
if (ret) {
ath6kl_warn("Failed to enable host sleep mode for sched scan: %d\n",
ret);
ret = ath6kl_wmi_enable_sched_scan_cmd(ar->wmi, vif->fw_vif_idx, true);
if (ret)
return ret;
}
ar->state = ATH6KL_STATE_SCHED_SCAN;
set_bit(SCHED_SCANNING, &vif->flags);
return ret;
return 0;
}
static int ath6kl_cfg80211_sscan_stop(struct wiphy *wiphy,
@ -3309,6 +3339,27 @@ static int ath6kl_cfg80211_set_bitrate(struct wiphy *wiphy,
mask);
}
static int ath6kl_cfg80211_set_txe_config(struct wiphy *wiphy,
struct net_device *dev,
u32 rate, u32 pkts, u32 intvl)
{
struct ath6kl *ar = ath6kl_priv(dev);
struct ath6kl_vif *vif = netdev_priv(dev);
if (vif->nw_type != INFRA_NETWORK ||
!test_bit(ATH6KL_FW_CAPABILITY_TX_ERR_NOTIFY, ar->fw_capabilities))
return -EOPNOTSUPP;
if (vif->sme_state != SME_CONNECTED)
return -ENOTCONN;
/* save this since the firmware won't report the interval */
vif->txe_intvl = intvl;
return ath6kl_wmi_set_txe_notify(ar->wmi, vif->fw_vif_idx,
rate, pkts, intvl);
}
static const struct ieee80211_txrx_stypes
ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = {
[NL80211_IFTYPE_STATION] = {
@ -3375,6 +3426,7 @@ static struct cfg80211_ops ath6kl_cfg80211_ops = {
.sched_scan_start = ath6kl_cfg80211_sscan_start,
.sched_scan_stop = ath6kl_cfg80211_sscan_stop,
.set_bitrate_mask = ath6kl_cfg80211_set_bitrate,
.set_cqm_txe_config = ath6kl_cfg80211_set_txe_config,
};
void ath6kl_cfg80211_stop(struct ath6kl_vif *vif)
@ -3395,16 +3447,22 @@ void ath6kl_cfg80211_stop(struct ath6kl_vif *vif)
break;
}
if (test_bit(CONNECTED, &vif->flags) ||
test_bit(CONNECT_PEND, &vif->flags))
if (vif->ar->state != ATH6KL_STATE_RECOVERY &&
(test_bit(CONNECTED, &vif->flags) ||
test_bit(CONNECT_PEND, &vif->flags)))
ath6kl_wmi_disconnect_cmd(vif->ar->wmi, vif->fw_vif_idx);
vif->sme_state = SME_DISCONNECTED;
clear_bit(CONNECTED, &vif->flags);
clear_bit(CONNECT_PEND, &vif->flags);
/* Stop netdev queues, needed during recovery */
netif_stop_queue(vif->ndev);
netif_carrier_off(vif->ndev);
/* disable scanning */
if (ath6kl_wmi_scanparams_cmd(vif->ar->wmi, vif->fw_vif_idx, 0xFFFF,
if (vif->ar->state != ATH6KL_STATE_RECOVERY &&
ath6kl_wmi_scanparams_cmd(vif->ar->wmi, vif->fw_vif_idx, 0xFFFF,
0, 0, 0, 0, 0, 0, 0, 0, 0) != 0)
ath6kl_warn("failed to disable scan during stop\n");
@ -3416,7 +3474,7 @@ void ath6kl_cfg80211_stop_all(struct ath6kl *ar)
struct ath6kl_vif *vif;
vif = ath6kl_vif_first(ar);
if (!vif) {
if (!vif && ar->state != ATH6KL_STATE_RECOVERY) {
/* save the current power mode before enabling power save */
ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode;
@ -3434,6 +3492,56 @@ void ath6kl_cfg80211_stop_all(struct ath6kl *ar)
ath6kl_cfg80211_stop(vif);
}
static int ath6kl_cfg80211_reg_notify(struct wiphy *wiphy,
struct regulatory_request *request)
{
struct ath6kl *ar = wiphy_priv(wiphy);
u32 rates[IEEE80211_NUM_BANDS];
int ret, i;
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
"cfg reg_notify %c%c%s%s initiator %d hint_type %d\n",
request->alpha2[0], request->alpha2[1],
request->intersect ? " intersect" : "",
request->processed ? " processed" : "",
request->initiator, request->user_reg_hint_type);
/*
* As firmware is not able intersect regdoms, we can only listen to
* cellular hints.
*/
if (request->user_reg_hint_type != NL80211_USER_REG_HINT_CELL_BASE)
return -EOPNOTSUPP;
ret = ath6kl_wmi_set_regdomain_cmd(ar->wmi, request->alpha2);
if (ret) {
ath6kl_err("failed to set regdomain: %d\n", ret);
return ret;
}
/*
* Firmware will apply the regdomain change only after a scan is
* issued and it will send a WMI_REGDOMAIN_EVENTID when it has been
* changed.
*/
for (i = 0; i < IEEE80211_NUM_BANDS; i++)
if (wiphy->bands[i])
rates[i] = (1 << wiphy->bands[i]->n_bitrates) - 1;
ret = ath6kl_wmi_beginscan_cmd(ar->wmi, 0, WMI_LONG_SCAN, false,
false, 0, ATH6KL_FG_SCAN_INTERVAL,
0, NULL, false, rates);
if (ret) {
ath6kl_err("failed to start scan for a regdomain change: %d\n",
ret);
return ret;
}
return 0;
}
static int ath6kl_cfg80211_vif_init(struct ath6kl_vif *vif)
{
vif->aggr_cntxt = aggr_init(vif);
@ -3506,9 +3614,13 @@ struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, const char *name,
vif->htcap[IEEE80211_BAND_5GHZ].ht_enable = true;
memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN);
if (fw_vif_idx != 0)
if (fw_vif_idx != 0) {
ndev->dev_addr[0] = (ndev->dev_addr[0] ^ (1 << fw_vif_idx)) |
0x2;
if (test_bit(ATH6KL_FW_CAPABILITY_CUSTOM_MAC_ADDR,
ar->fw_capabilities))
ndev->dev_addr[4] ^= 0x80;
}
init_netdev(ndev);
@ -3562,6 +3674,12 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
BIT(NL80211_IFTYPE_P2P_CLIENT);
}
if (config_enabled(CONFIG_ATH6KL_REGDOMAIN) &&
test_bit(ATH6KL_FW_CAPABILITY_REGDOMAIN, ar->fw_capabilities)) {
wiphy->reg_notifier = ath6kl_cfg80211_reg_notify;
ar->wiphy->features |= NL80211_FEATURE_CELL_BASE_REG_HINTS;
}
/* max num of ssids that can be probed during scanning */
wiphy->max_scan_ssids = MAX_PROBED_SSIDS;
@ -3607,7 +3725,7 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
ath6kl_band_5ghz.ht_cap.ht_supported = false;
}
if (ar->hw.flags & ATH6KL_HW_FLAG_64BIT_RATES) {
if (ar->hw.flags & ATH6KL_HW_64BIT_RATES) {
ath6kl_band_2ghz.ht_cap.mcs.rx_mask[0] = 0xff;
ath6kl_band_5ghz.ht_cap.mcs.rx_mask[0] = 0xff;
ath6kl_band_2ghz.ht_cap.mcs.rx_mask[1] = 0xff;
@ -3646,7 +3764,7 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN, ar->fw_capabilities))
if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN_V2, ar->fw_capabilities))
ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
if (test_bit(ATH6KL_FW_CAPABILITY_INACTIVITY_TIMEOUT,

View File

@ -22,7 +22,6 @@ enum ath6kl_cfg_suspend_mode {
ATH6KL_CFG_SUSPEND_DEEPSLEEP,
ATH6KL_CFG_SUSPEND_CUTPOWER,
ATH6KL_CFG_SUSPEND_WOW,
ATH6KL_CFG_SUSPEND_SCHED_SCAN,
};
struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, const char *name,

View File

@ -33,6 +33,8 @@ static unsigned int wow_mode;
static unsigned int uart_debug;
static unsigned int ath6kl_p2p;
static unsigned int testmode;
static unsigned int recovery_enable;
static unsigned int heart_beat_poll;
module_param(debug_mask, uint, 0644);
module_param(suspend_mode, uint, 0644);
@ -40,6 +42,12 @@ module_param(wow_mode, uint, 0644);
module_param(uart_debug, uint, 0644);
module_param(ath6kl_p2p, uint, 0644);
module_param(testmode, uint, 0644);
module_param(recovery_enable, uint, 0644);
module_param(heart_beat_poll, uint, 0644);
MODULE_PARM_DESC(recovery_enable, "Enable recovery from firmware error");
MODULE_PARM_DESC(heart_beat_poll, "Enable fw error detection periodic" \
"polling. This also specifies the polling interval in" \
"msecs. Set reocvery_enable for this to be effective");
void ath6kl_core_tx_complete(struct ath6kl *ar, struct sk_buff *skb)
{
@ -202,6 +210,17 @@ int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type)
ath6kl_dbg(ATH6KL_DBG_TRC, "%s: name=%s dev=0x%p, ar=0x%p\n",
__func__, wdev->netdev->name, wdev->netdev, ar);
ar->fw_recovery.enable = !!recovery_enable;
if (!ar->fw_recovery.enable)
return ret;
if (heart_beat_poll &&
test_bit(ATH6KL_FW_CAPABILITY_HEART_BEAT_POLL,
ar->fw_capabilities))
ar->fw_recovery.hb_poll = heart_beat_poll;
ath6kl_recovery_init(ar);
return ret;
err_rxbuf_cleanup:
@ -291,6 +310,8 @@ void ath6kl_core_cleanup(struct ath6kl *ar)
{
ath6kl_hif_power_off(ar);
ath6kl_recovery_cleanup(ar);
destroy_workqueue(ar->ath6kl_wq);
if (ar->htc_target)

View File

@ -115,6 +115,27 @@ enum ath6kl_fw_capability {
*/
ATH6KL_FW_CAPABILITY_SCHED_SCAN_MATCH_LIST,
/* Firmware supports filtering BSS results by RSSI */
ATH6KL_FW_CAPABILITY_RSSI_SCAN_THOLD,
/* FW sets mac_addr[4] ^= 0x80 for newly created interfaces */
ATH6KL_FW_CAPABILITY_CUSTOM_MAC_ADDR,
/* Firmware supports TX error rate notification */
ATH6KL_FW_CAPABILITY_TX_ERR_NOTIFY,
/* supports WMI_SET_REGDOMAIN_CMDID command */
ATH6KL_FW_CAPABILITY_REGDOMAIN,
/* Firmware supports sched scan decoupled from host sleep */
ATH6KL_FW_CAPABILITY_SCHED_SCAN_V2,
/*
* Firmware capability for hang detection through heart beat
* challenge messages.
*/
ATH6KL_FW_CAPABILITY_HEART_BEAT_POLL,
/* this needs to be last */
ATH6KL_FW_CAPABILITY_MAX,
};
@ -128,11 +149,15 @@ struct ath6kl_fw_ie {
};
enum ath6kl_hw_flags {
ATH6KL_HW_FLAG_64BIT_RATES = BIT(0),
ATH6KL_HW_64BIT_RATES = BIT(0),
ATH6KL_HW_AP_INACTIVITY_MINS = BIT(1),
ATH6KL_HW_MAP_LP_ENDPOINT = BIT(2),
ATH6KL_HW_SDIO_CRC_ERROR_WAR = BIT(3),
};
#define ATH6KL_FW_API2_FILE "fw-2.bin"
#define ATH6KL_FW_API3_FILE "fw-3.bin"
#define ATH6KL_FW_API4_FILE "fw-4.bin"
/* AR6003 1.0 definitions */
#define AR6003_HW_1_0_VERSION 0x300002ba
@ -186,6 +211,13 @@ enum ath6kl_hw_flags {
#define AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE \
AR6004_HW_1_2_FW_DIR "/bdata.bin"
/* AR6004 1.3 definitions */
#define AR6004_HW_1_3_VERSION 0x31c8088a
#define AR6004_HW_1_3_FW_DIR "ath6k/AR6004/hw1.3"
#define AR6004_HW_1_3_FIRMWARE_FILE "fw.ram.bin"
#define AR6004_HW_1_3_BOARD_DATA_FILE "ath6k/AR6004/hw1.3/bdata.bin"
#define AR6004_HW_1_3_DEFAULT_BOARD_DATA_FILE "ath6k/AR6004/hw1.3/bdata.bin"
/* Per STA data, used in AP mode */
#define STA_PS_AWAKE BIT(0)
#define STA_PS_SLEEP BIT(1)
@ -536,6 +568,7 @@ enum ath6kl_vif_state {
HOST_SLEEP_MODE_CMD_PROCESSED,
NETDEV_MCAST_ALL_ON,
NETDEV_MCAST_ALL_OFF,
SCHED_SCANNING,
};
struct ath6kl_vif {
@ -580,11 +613,13 @@ struct ath6kl_vif {
u16 assoc_bss_beacon_int;
u16 listen_intvl_t;
u16 bmiss_time_t;
u32 txe_intvl;
u16 bg_scan_period;
u8 assoc_bss_dtim_period;
struct net_device_stats net_stats;
struct target_stats target_stats;
struct wmi_connect_cmd profile;
u16 rsn_capab;
struct list_head mc_filter;
};
@ -609,6 +644,7 @@ enum ath6kl_dev_state {
SKIP_SCAN,
ROAM_TBL_PEND,
FIRST_BOOT,
RECOVERY_CLEANUP,
};
enum ath6kl_state {
@ -619,7 +655,16 @@ enum ath6kl_state {
ATH6KL_STATE_DEEPSLEEP,
ATH6KL_STATE_CUTPOWER,
ATH6KL_STATE_WOW,
ATH6KL_STATE_SCHED_SCAN,
ATH6KL_STATE_RECOVERY,
};
/* Fw error recovery */
#define ATH6KL_HB_RESP_MISS_THRES 5
enum ath6kl_fw_err {
ATH6KL_FW_ASSERT,
ATH6KL_FW_HB_RESP_FAILURE,
ATH6KL_FW_EP_FULL,
};
struct ath6kl {
@ -679,6 +724,7 @@ struct ath6kl {
struct ath6kl_req_key ap_mode_bkey;
struct sk_buff_head mcastpsq;
u32 want_ch_switch;
u16 last_ch;
/*
* FIXME: protects access to mcastpsq but is actually useless as
@ -764,6 +810,17 @@ struct ath6kl {
bool wiphy_registered;
struct ath6kl_fw_recovery {
struct work_struct recovery_work;
unsigned long err_reason;
unsigned long hb_poll;
struct timer_list hb_timer;
u32 seq_num;
bool hb_pending;
u8 hb_misscnt;
bool enable;
} fw_recovery;
#ifdef CONFIG_ATH6KL_DEBUG
struct {
struct sk_buff_head fwlog_queue;
@ -899,4 +956,12 @@ int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type);
void ath6kl_core_cleanup(struct ath6kl *ar);
void ath6kl_core_destroy(struct ath6kl *ar);
/* Fw error recovery */
void ath6kl_init_hw_restart(struct ath6kl *ar);
void ath6kl_recovery_err_notify(struct ath6kl *ar, enum ath6kl_fw_err reason);
void ath6kl_recovery_hb_event(struct ath6kl *ar, u32 cookie);
void ath6kl_recovery_init(struct ath6kl *ar);
void ath6kl_recovery_cleanup(struct ath6kl *ar);
void ath6kl_recovery_suspend(struct ath6kl *ar);
void ath6kl_recovery_resume(struct ath6kl *ar);
#endif /* CORE_H */

View File

@ -44,6 +44,7 @@ enum ATH6K_DEBUG_MASK {
ATH6KL_DBG_SUSPEND = BIT(20),
ATH6KL_DBG_USB = BIT(21),
ATH6KL_DBG_USB_BULK = BIT(22),
ATH6KL_DBG_RECOVERY = BIT(23),
ATH6KL_DBG_ANY = 0xffffffff /* enable all logs */
};

View File

@ -136,6 +136,7 @@ static int ath6kl_hif_proc_dbg_intr(struct ath6kl_device *dev)
ath6kl_hif_dump_fw_crash(dev->ar);
ath6kl_read_fwlogs(dev->ar);
ath6kl_recovery_err_notify(dev->ar, ATH6KL_FW_ASSERT);
return ret;
}
@ -338,8 +339,7 @@ static int ath6kl_hif_proc_err_intr(struct ath6kl_device *dev)
status = hif_read_write_sync(dev->ar, ERROR_INT_STATUS_ADDRESS,
reg_buf, 4, HIF_WR_SYNC_BYTE_FIX);
if (status)
WARN_ON(1);
WARN_ON(status);
return status;
}
@ -383,8 +383,7 @@ static int ath6kl_hif_proc_cpu_intr(struct ath6kl_device *dev)
status = hif_read_write_sync(dev->ar, CPU_INT_STATUS_ADDRESS,
reg_buf, 4, HIF_WR_SYNC_BYTE_FIX);
if (status)
WARN_ON(1);
WARN_ON(status);
return status;
}
@ -695,11 +694,6 @@ int ath6kl_hif_setup(struct ath6kl_device *dev)
ath6kl_dbg(ATH6KL_DBG_HIF, "hif block size %d mbox addr 0x%x\n",
dev->htc_cnxt->block_sz, dev->ar->mbox_info.htc_addr);
/* usb doesn't support enabling interrupts */
/* FIXME: remove check once USB support is implemented */
if (dev->ar->hif_type == ATH6KL_HIF_TYPE_USB)
return 0;
status = ath6kl_hif_disable_intrs(dev);
fail_setup:

View File

@ -2492,7 +2492,8 @@ static int ath6kl_htc_mbox_conn_service(struct htc_target *target,
max_msg_sz = le16_to_cpu(resp_msg->max_msg_sz);
}
if (assigned_ep >= ENDPOINT_MAX || !max_msg_sz) {
if (WARN_ON_ONCE(assigned_ep == ENDPOINT_UNUSED ||
assigned_ep >= ENDPOINT_MAX || !max_msg_sz)) {
status = -ENOMEM;
goto fail_tx;
}
@ -2655,12 +2656,6 @@ static int ath6kl_htc_mbox_wait_target(struct htc_target *target)
struct htc_service_connect_resp resp;
int status;
/* FIXME: remove once USB support is implemented */
if (target->dev->ar->hif_type == ATH6KL_HIF_TYPE_USB) {
ath6kl_err("HTC doesn't support USB yet. Patience!\n");
return -EOPNOTSUPP;
}
/* we should be getting 1 control message that the target is ready */
packet = htc_wait_for_ctrl_msg(target);
@ -2890,9 +2885,7 @@ static void ath6kl_htc_mbox_cleanup(struct htc_target *target)
{
struct htc_packet *packet, *tmp_packet;
/* FIXME: remove check once USB support is implemented */
if (target->dev->ar->hif_type != ATH6KL_HIF_TYPE_USB)
ath6kl_hif_cleanup_scatter(target->dev->ar);
ath6kl_hif_cleanup_scatter(target->dev->ar);
list_for_each_entry_safe(packet, tmp_packet,
&target->free_ctrl_txbuf, list) {

View File

@ -374,9 +374,8 @@ static enum htc_send_queue_result htc_try_send(struct htc_target *target,
packet = list_first_entry(txq,
struct htc_packet,
list);
list_del(&packet->list);
/* insert into local queue */
list_add_tail(&packet->list, &send_queue);
/* move to local queue */
list_move_tail(&packet->list, &send_queue);
}
/*
@ -399,11 +398,10 @@ static enum htc_send_queue_result htc_try_send(struct htc_target *target,
* for cleanup */
} else {
/* callback wants to keep this packet,
* remove from caller's queue */
list_del(&packet->list);
/* put it in the send queue */
list_add_tail(&packet->list,
&send_queue);
* move from caller's queue to the send
* queue */
list_move_tail(&packet->list,
&send_queue);
}
}

View File

@ -42,7 +42,7 @@ static const struct ath6kl_hw hw_list[] = {
.reserved_ram_size = 6912,
.refclk_hz = 26000000,
.uarttx_pin = 8,
.flags = 0,
.flags = ATH6KL_HW_SDIO_CRC_ERROR_WAR,
/* hw2.0 needs override address hardcoded */
.app_start_override_addr = 0x944C00,
@ -68,7 +68,7 @@ static const struct ath6kl_hw hw_list[] = {
.refclk_hz = 26000000,
.uarttx_pin = 8,
.testscript_addr = 0x57ef74,
.flags = 0,
.flags = ATH6KL_HW_SDIO_CRC_ERROR_WAR,
.fw = {
.dir = AR6003_HW_2_1_1_FW_DIR,
@ -93,7 +93,8 @@ static const struct ath6kl_hw hw_list[] = {
.board_addr = 0x433900,
.refclk_hz = 26000000,
.uarttx_pin = 11,
.flags = ATH6KL_HW_FLAG_64BIT_RATES,
.flags = ATH6KL_HW_64BIT_RATES |
ATH6KL_HW_AP_INACTIVITY_MINS,
.fw = {
.dir = AR6004_HW_1_0_FW_DIR,
@ -113,8 +114,8 @@ static const struct ath6kl_hw hw_list[] = {
.board_addr = 0x43d400,
.refclk_hz = 40000000,
.uarttx_pin = 11,
.flags = ATH6KL_HW_FLAG_64BIT_RATES,
.flags = ATH6KL_HW_64BIT_RATES |
ATH6KL_HW_AP_INACTIVITY_MINS,
.fw = {
.dir = AR6004_HW_1_1_FW_DIR,
.fw = AR6004_HW_1_1_FIRMWARE_FILE,
@ -133,7 +134,8 @@ static const struct ath6kl_hw hw_list[] = {
.board_addr = 0x435c00,
.refclk_hz = 40000000,
.uarttx_pin = 11,
.flags = ATH6KL_HW_FLAG_64BIT_RATES,
.flags = ATH6KL_HW_64BIT_RATES |
ATH6KL_HW_AP_INACTIVITY_MINS,
.fw = {
.dir = AR6004_HW_1_2_FW_DIR,
@ -142,6 +144,28 @@ static const struct ath6kl_hw hw_list[] = {
.fw_board = AR6004_HW_1_2_BOARD_DATA_FILE,
.fw_default_board = AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE,
},
{
.id = AR6004_HW_1_3_VERSION,
.name = "ar6004 hw 1.3",
.dataset_patch_addr = 0x437860,
.app_load_addr = 0x1234,
.board_ext_data_addr = 0x437000,
.reserved_ram_size = 7168,
.board_addr = 0x436400,
.refclk_hz = 40000000,
.uarttx_pin = 11,
.flags = ATH6KL_HW_64BIT_RATES |
ATH6KL_HW_AP_INACTIVITY_MINS |
ATH6KL_HW_MAP_LP_ENDPOINT,
.fw = {
.dir = AR6004_HW_1_3_FW_DIR,
.fw = AR6004_HW_1_3_FIRMWARE_FILE,
},
.fw_board = AR6004_HW_1_3_BOARD_DATA_FILE,
.fw_default_board = AR6004_HW_1_3_DEFAULT_BOARD_DATA_FILE,
},
};
/*
@ -337,7 +361,7 @@ static int ath6kl_init_service_ep(struct ath6kl *ar)
if (ath6kl_connectservice(ar, &connect, "WMI DATA BK"))
return -EIO;
/* connect to Video service, map this to to HI PRI */
/* connect to Video service, map this to HI PRI */
connect.svc_id = WMI_DATA_VI_SVC;
if (ath6kl_connectservice(ar, &connect, "WMI DATA VI"))
return -EIO;
@ -1088,6 +1112,12 @@ int ath6kl_init_fetch_firmwares(struct ath6kl *ar)
if (ret)
return ret;
ret = ath6kl_fetch_fw_apin(ar, ATH6KL_FW_API4_FILE);
if (ret == 0) {
ar->fw_api = 4;
goto out;
}
ret = ath6kl_fetch_fw_apin(ar, ATH6KL_FW_API3_FILE);
if (ret == 0) {
ar->fw_api = 3;
@ -1401,8 +1431,7 @@ static int ath6kl_init_upload(struct ath6kl *ar)
return status;
/* WAR to avoid SDIO CRC err */
if (ar->version.target_ver == AR6003_HW_2_0_VERSION ||
ar->version.target_ver == AR6003_HW_2_1_1_VERSION) {
if (ar->hw.flags & ATH6KL_HW_SDIO_CRC_ERROR_WAR) {
ath6kl_err("temporary war to avoid sdio crc error\n");
param = 0x28;
@ -1520,7 +1549,7 @@ static const char *ath6kl_init_get_hif_name(enum ath6kl_hif_type type)
return NULL;
}
int ath6kl_init_hw_start(struct ath6kl *ar)
static int __ath6kl_init_hw_start(struct ath6kl *ar)
{
long timeleft;
int ret, i;
@ -1616,8 +1645,6 @@ int ath6kl_init_hw_start(struct ath6kl *ar)
goto err_htc_stop;
}
ar->state = ATH6KL_STATE_ON;
return 0;
err_htc_stop:
@ -1630,7 +1657,18 @@ err_power_off:
return ret;
}
int ath6kl_init_hw_stop(struct ath6kl *ar)
int ath6kl_init_hw_start(struct ath6kl *ar)
{
int err;
err = __ath6kl_init_hw_start(ar);
if (err)
return err;
ar->state = ATH6KL_STATE_ON;
return 0;
}
static int __ath6kl_init_hw_stop(struct ath6kl *ar)
{
int ret;
@ -1646,11 +1684,37 @@ int ath6kl_init_hw_stop(struct ath6kl *ar)
if (ret)
ath6kl_warn("failed to power off hif: %d\n", ret);
ar->state = ATH6KL_STATE_OFF;
return 0;
}
int ath6kl_init_hw_stop(struct ath6kl *ar)
{
int err;
err = __ath6kl_init_hw_stop(ar);
if (err)
return err;
ar->state = ATH6KL_STATE_OFF;
return 0;
}
void ath6kl_init_hw_restart(struct ath6kl *ar)
{
clear_bit(WMI_READY, &ar->flag);
ath6kl_cfg80211_stop_all(ar);
if (__ath6kl_init_hw_stop(ar)) {
ath6kl_dbg(ATH6KL_DBG_RECOVERY, "Failed to stop during fw error recovery\n");
return;
}
if (__ath6kl_init_hw_start(ar)) {
ath6kl_dbg(ATH6KL_DBG_RECOVERY, "Failed to restart during fw error recovery\n");
return;
}
}
/* FIXME: move this to cfg80211.c and rename to ath6kl_cfg80211_vif_stop() */
void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready)
{

View File

@ -293,13 +293,17 @@ int ath6kl_read_fwlogs(struct ath6kl *ar)
}
address = TARG_VTOP(ar->target_type, debug_hdr_addr);
ath6kl_diag_read(ar, address, &debug_hdr, sizeof(debug_hdr));
ret = ath6kl_diag_read(ar, address, &debug_hdr, sizeof(debug_hdr));
if (ret)
goto out;
address = TARG_VTOP(ar->target_type,
le32_to_cpu(debug_hdr.dbuf_addr));
firstbuf = address;
dropped = le32_to_cpu(debug_hdr.dropped);
ath6kl_diag_read(ar, address, &debug_buf, sizeof(debug_buf));
ret = ath6kl_diag_read(ar, address, &debug_buf, sizeof(debug_buf));
if (ret)
goto out;
loop = 100;
@ -322,7 +326,8 @@ int ath6kl_read_fwlogs(struct ath6kl *ar)
address = TARG_VTOP(ar->target_type,
le32_to_cpu(debug_buf.next));
ath6kl_diag_read(ar, address, &debug_buf, sizeof(debug_buf));
ret = ath6kl_diag_read(ar, address, &debug_buf,
sizeof(debug_buf));
if (ret)
goto out;
@ -436,12 +441,9 @@ void ath6kl_connect_ap_mode_bss(struct ath6kl_vif *vif, u16 channel)
break;
}
if (ar->want_ch_switch & (1 << vif->fw_vif_idx)) {
ar->want_ch_switch &= ~(1 << vif->fw_vif_idx);
if (ar->last_ch != channel)
/* we actually don't know the phymode, default to HT20 */
ath6kl_cfg80211_ch_switch_notify(vif, channel,
WMI_11G_HT20);
}
ath6kl_cfg80211_ch_switch_notify(vif, channel, WMI_11G_HT20);
ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx, NONE_BSS_FILTER, 0);
set_bit(CONNECTED, &vif->flags);
@ -606,6 +608,18 @@ static int ath6kl_commit_ch_switch(struct ath6kl_vif *vif, u16 channel)
switch (vif->nw_type) {
case AP_NETWORK:
/*
* reconfigure any saved RSN IE capabilites in the beacon /
* probe response to stay in sync with the supplicant.
*/
if (vif->rsn_capab &&
test_bit(ATH6KL_FW_CAPABILITY_RSN_CAP_OVERRIDE,
ar->fw_capabilities))
ath6kl_wmi_set_ie_cmd(ar->wmi, vif->fw_vif_idx,
WLAN_EID_RSN, WMI_RSN_IE_CAPB,
(const u8 *) &vif->rsn_capab,
sizeof(vif->rsn_capab));
return ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx,
&vif->profile);
default:
@ -628,6 +642,9 @@ static void ath6kl_check_ch_switch(struct ath6kl *ar, u16 channel)
if (ar->want_ch_switch & (1 << vif->fw_vif_idx))
res = ath6kl_commit_ch_switch(vif, channel);
/* if channel switch failed, oh well we tried */
ar->want_ch_switch &= ~(1 << vif->fw_vif_idx);
if (res)
ath6kl_err("channel switch failed nw_type %d res %d\n",
vif->nw_type, res);
@ -981,8 +998,25 @@ void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason, u8 *bssid,
if (vif->nw_type == AP_NETWORK) {
/* disconnect due to other STA vif switching channels */
if (reason == BSS_DISCONNECTED &&
prot_reason_status == WMI_AP_REASON_STA_ROAM)
prot_reason_status == WMI_AP_REASON_STA_ROAM) {
ar->want_ch_switch |= 1 << vif->fw_vif_idx;
/* bail back to this channel if STA vif fails connect */
ar->last_ch = le16_to_cpu(vif->profile.ch);
}
if (prot_reason_status == WMI_AP_REASON_MAX_STA) {
/* send max client reached notification to user space */
cfg80211_conn_failed(vif->ndev, bssid,
NL80211_CONN_FAIL_MAX_CLIENTS,
GFP_KERNEL);
}
if (prot_reason_status == WMI_AP_REASON_ACL) {
/* send blocked client notification to user space */
cfg80211_conn_failed(vif->ndev, bssid,
NL80211_CONN_FAIL_BLOCKED_CLIENT,
GFP_KERNEL);
}
if (!ath6kl_remove_sta(ar, bssid, prot_reason_status))
return;
@ -1041,6 +1075,9 @@ void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason, u8 *bssid,
}
}
/* restart disconnected concurrent vifs waiting for new channel */
ath6kl_check_ch_switch(ar, ar->last_ch);
/* update connect & link status atomically */
spin_lock_bh(&vif->if_lock);
clear_bit(CONNECTED, &vif->flags);

View File

@ -0,0 +1,160 @@
/*
* Copyright (c) 2012 Qualcomm Atheros, Inc.
*
* 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.
*/
#include "core.h"
#include "cfg80211.h"
#include "debug.h"
static void ath6kl_recovery_work(struct work_struct *work)
{
struct ath6kl *ar = container_of(work, struct ath6kl,
fw_recovery.recovery_work);
ar->state = ATH6KL_STATE_RECOVERY;
del_timer_sync(&ar->fw_recovery.hb_timer);
ath6kl_init_hw_restart(ar);
ar->state = ATH6KL_STATE_ON;
clear_bit(WMI_CTRL_EP_FULL, &ar->flag);
ar->fw_recovery.err_reason = 0;
if (ar->fw_recovery.hb_poll)
mod_timer(&ar->fw_recovery.hb_timer, jiffies +
msecs_to_jiffies(ar->fw_recovery.hb_poll));
}
void ath6kl_recovery_err_notify(struct ath6kl *ar, enum ath6kl_fw_err reason)
{
if (!ar->fw_recovery.enable)
return;
ath6kl_dbg(ATH6KL_DBG_RECOVERY, "Fw error detected, reason:%d\n",
reason);
set_bit(reason, &ar->fw_recovery.err_reason);
if (!test_bit(RECOVERY_CLEANUP, &ar->flag) &&
ar->state != ATH6KL_STATE_RECOVERY)
queue_work(ar->ath6kl_wq, &ar->fw_recovery.recovery_work);
}
void ath6kl_recovery_hb_event(struct ath6kl *ar, u32 cookie)
{
if (cookie == ar->fw_recovery.seq_num)
ar->fw_recovery.hb_pending = false;
}
static void ath6kl_recovery_hb_timer(unsigned long data)
{
struct ath6kl *ar = (struct ath6kl *) data;
int err;
if (test_bit(RECOVERY_CLEANUP, &ar->flag) ||
(ar->state == ATH6KL_STATE_RECOVERY))
return;
if (ar->fw_recovery.hb_pending)
ar->fw_recovery.hb_misscnt++;
else
ar->fw_recovery.hb_misscnt = 0;
if (ar->fw_recovery.hb_misscnt > ATH6KL_HB_RESP_MISS_THRES) {
ar->fw_recovery.hb_misscnt = 0;
ar->fw_recovery.seq_num = 0;
ar->fw_recovery.hb_pending = false;
ath6kl_recovery_err_notify(ar, ATH6KL_FW_HB_RESP_FAILURE);
return;
}
ar->fw_recovery.seq_num++;
ar->fw_recovery.hb_pending = true;
err = ath6kl_wmi_get_challenge_resp_cmd(ar->wmi,
ar->fw_recovery.seq_num, 0);
if (err)
ath6kl_warn("Failed to send hb challenge request, err:%d\n",
err);
mod_timer(&ar->fw_recovery.hb_timer, jiffies +
msecs_to_jiffies(ar->fw_recovery.hb_poll));
}
void ath6kl_recovery_init(struct ath6kl *ar)
{
struct ath6kl_fw_recovery *recovery = &ar->fw_recovery;
clear_bit(RECOVERY_CLEANUP, &ar->flag);
INIT_WORK(&recovery->recovery_work, ath6kl_recovery_work);
recovery->seq_num = 0;
recovery->hb_misscnt = 0;
ar->fw_recovery.hb_pending = false;
ar->fw_recovery.hb_timer.function = ath6kl_recovery_hb_timer;
ar->fw_recovery.hb_timer.data = (unsigned long) ar;
init_timer_deferrable(&ar->fw_recovery.hb_timer);
if (ar->fw_recovery.hb_poll)
mod_timer(&ar->fw_recovery.hb_timer, jiffies +
msecs_to_jiffies(ar->fw_recovery.hb_poll));
}
void ath6kl_recovery_cleanup(struct ath6kl *ar)
{
if (!ar->fw_recovery.enable)
return;
set_bit(RECOVERY_CLEANUP, &ar->flag);
del_timer_sync(&ar->fw_recovery.hb_timer);
cancel_work_sync(&ar->fw_recovery.recovery_work);
}
void ath6kl_recovery_suspend(struct ath6kl *ar)
{
if (!ar->fw_recovery.enable)
return;
ath6kl_recovery_cleanup(ar);
if (!ar->fw_recovery.err_reason)
return;
/* Process pending fw error detection */
ar->fw_recovery.err_reason = 0;
WARN_ON(ar->state != ATH6KL_STATE_ON);
ar->state = ATH6KL_STATE_RECOVERY;
ath6kl_init_hw_restart(ar);
ar->state = ATH6KL_STATE_ON;
}
void ath6kl_recovery_resume(struct ath6kl *ar)
{
if (!ar->fw_recovery.enable)
return;
clear_bit(RECOVERY_CLEANUP, &ar->flag);
if (!ar->fw_recovery.hb_poll)
return;
ar->fw_recovery.hb_pending = false;
ar->fw_recovery.seq_num = 0;
ar->fw_recovery.hb_misscnt = 0;
mod_timer(&ar->fw_recovery.hb_timer,
jiffies + msecs_to_jiffies(ar->fw_recovery.hb_poll));
}

View File

@ -709,7 +709,7 @@ static int ath6kl_sdio_enable_scatter(struct ath6kl *ar)
{
struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
struct htc_target *target = ar->htc_target;
int ret;
int ret = 0;
bool virt_scat = false;
if (ar_sdio->scatter_enabled)
@ -844,22 +844,6 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
bool try_deepsleep = false;
int ret;
if (ar->state == ATH6KL_STATE_SCHED_SCAN) {
ath6kl_dbg(ATH6KL_DBG_SUSPEND, "sched scan is in progress\n");
ret = ath6kl_set_sdio_pm_caps(ar);
if (ret)
goto cut_pwr;
ret = ath6kl_cfg80211_suspend(ar,
ATH6KL_CFG_SUSPEND_SCHED_SCAN,
NULL);
if (ret)
goto cut_pwr;
return 0;
}
if (ar->suspend_mode == WLAN_POWER_STATE_WOW ||
(!ar->suspend_mode && wow)) {
@ -942,14 +926,14 @@ static int ath6kl_sdio_resume(struct ath6kl *ar)
case ATH6KL_STATE_WOW:
break;
case ATH6KL_STATE_SCHED_SCAN:
break;
case ATH6KL_STATE_SUSPENDING:
break;
case ATH6KL_STATE_RESUMING:
break;
case ATH6KL_STATE_RECOVERY:
break;
}
ath6kl_cfg80211_resume(ar);
@ -1462,3 +1446,6 @@ MODULE_FIRMWARE(AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE);
MODULE_FIRMWARE(AR6004_HW_1_2_FW_DIR "/" AR6004_HW_1_2_FIRMWARE_FILE);
MODULE_FIRMWARE(AR6004_HW_1_2_BOARD_DATA_FILE);
MODULE_FIRMWARE(AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE);
MODULE_FIRMWARE(AR6004_HW_1_3_FW_DIR "/" AR6004_HW_1_3_FIRMWARE_FILE);
MODULE_FIRMWARE(AR6004_HW_1_3_BOARD_DATA_FILE);
MODULE_FIRMWARE(AR6004_HW_1_3_DEFAULT_BOARD_DATA_FILE);

View File

@ -288,8 +288,16 @@ int ath6kl_control_tx(void *devt, struct sk_buff *skb,
int status = 0;
struct ath6kl_cookie *cookie = NULL;
if (WARN_ON_ONCE(ar->state == ATH6KL_STATE_WOW))
if (WARN_ON_ONCE(ar->state == ATH6KL_STATE_WOW)) {
dev_kfree_skb(skb);
return -EACCES;
}
if (WARN_ON_ONCE(eid == ENDPOINT_UNUSED ||
eid >= ENDPOINT_MAX)) {
status = -EINVAL;
goto fail_ctrl_tx;
}
spin_lock_bh(&ar->lock);
@ -591,6 +599,7 @@ enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target,
*/
set_bit(WMI_CTRL_EP_FULL, &ar->flag);
ath6kl_err("wmi ctrl ep is full\n");
ath6kl_recovery_err_notify(ar, ATH6KL_FW_EP_FULL);
return action;
}
@ -695,22 +704,31 @@ void ath6kl_tx_complete(struct htc_target *target,
list);
list_del(&packet->list);
if (WARN_ON_ONCE(packet->endpoint == ENDPOINT_UNUSED ||
packet->endpoint >= ENDPOINT_MAX))
continue;
ath6kl_cookie = (struct ath6kl_cookie *)packet->pkt_cntxt;
if (!ath6kl_cookie)
goto fatal;
if (WARN_ON_ONCE(!ath6kl_cookie))
continue;
status = packet->status;
skb = ath6kl_cookie->skb;
eid = packet->endpoint;
map_no = ath6kl_cookie->map_no;
if (!skb || !skb->data)
goto fatal;
if (WARN_ON_ONCE(!skb || !skb->data)) {
dev_kfree_skb(skb);
ath6kl_free_cookie(ar, ath6kl_cookie);
continue;
}
__skb_queue_tail(&skb_queue, skb);
if (!status && (packet->act_len != skb->len))
goto fatal;
if (WARN_ON_ONCE(!status && (packet->act_len != skb->len))) {
ath6kl_free_cookie(ar, ath6kl_cookie);
continue;
}
ar->tx_pending[eid]--;
@ -792,11 +810,6 @@ void ath6kl_tx_complete(struct htc_target *target,
wake_up(&ar->event_wq);
return;
fatal:
WARN_ON(1);
spin_unlock_bh(&ar->lock);
return;
}
void ath6kl_tx_data_cleanup(struct ath6kl *ar)
@ -885,8 +898,11 @@ void ath6kl_rx_refill(struct htc_target *target, enum htc_endpoint_id endpoint)
break;
packet = (struct htc_packet *) skb->head;
if (!IS_ALIGNED((unsigned long) skb->data, 4))
if (!IS_ALIGNED((unsigned long) skb->data, 4)) {
size_t len = skb_headlen(skb);
skb->data = PTR_ALIGN(skb->data - 4, 4);
skb_set_tail_pointer(skb, len);
}
set_htc_rxpkt_info(packet, skb, skb->data,
ATH6KL_BUFFER_SIZE, endpoint);
packet->skb = skb;
@ -908,8 +924,11 @@ void ath6kl_refill_amsdu_rxbufs(struct ath6kl *ar, int count)
return;
packet = (struct htc_packet *) skb->head;
if (!IS_ALIGNED((unsigned long) skb->data, 4))
if (!IS_ALIGNED((unsigned long) skb->data, 4)) {
size_t len = skb_headlen(skb);
skb->data = PTR_ALIGN(skb->data - 4, 4);
skb_set_tail_pointer(skb, len);
}
set_htc_rxpkt_info(packet, skb, skb->data,
ATH6KL_AMSDU_BUFFER_SIZE, 0);
packet->skb = skb;

View File

@ -185,9 +185,10 @@ static int ath6kl_usb_alloc_pipe_resources(struct ath6kl_usb_pipe *pipe,
for (i = 0; i < urb_cnt; i++) {
urb_context = kzalloc(sizeof(struct ath6kl_urb_context),
GFP_KERNEL);
if (urb_context == NULL)
/* FIXME: set status to -ENOMEM */
break;
if (urb_context == NULL) {
status = -ENOMEM;
goto fail_alloc_pipe_resources;
}
urb_context->pipe = pipe;
@ -204,6 +205,7 @@ static int ath6kl_usb_alloc_pipe_resources(struct ath6kl_usb_pipe *pipe,
pipe->logical_pipe_num, pipe->usb_pipe_handle,
pipe->urb_alloc);
fail_alloc_pipe_resources:
return status;
}
@ -803,7 +805,11 @@ static int ath6kl_usb_map_service_pipe(struct ath6kl *ar, u16 svc_id,
*dl_pipe = ATH6KL_USB_PIPE_RX_DATA;
break;
case WMI_DATA_VI_SVC:
*ul_pipe = ATH6KL_USB_PIPE_TX_DATA_MP;
if (ar->hw.flags & ATH6KL_HW_MAP_LP_ENDPOINT)
*ul_pipe = ATH6KL_USB_PIPE_TX_DATA_LP;
else
*ul_pipe = ATH6KL_USB_PIPE_TX_DATA_MP;
/*
* Disable rxdata2 directly, it will be enabled
* if FW enable rxdata2
@ -811,7 +817,11 @@ static int ath6kl_usb_map_service_pipe(struct ath6kl *ar, u16 svc_id,
*dl_pipe = ATH6KL_USB_PIPE_RX_DATA;
break;
case WMI_DATA_VO_SVC:
*ul_pipe = ATH6KL_USB_PIPE_TX_DATA_HP;
if (ar->hw.flags & ATH6KL_HW_MAP_LP_ENDPOINT)
*ul_pipe = ATH6KL_USB_PIPE_TX_DATA_LP;
else
*ul_pipe = ATH6KL_USB_PIPE_TX_DATA_MP;
/*
* Disable rxdata2 directly, it will be enabled
* if FW enable rxdata2
@ -1196,7 +1206,14 @@ static struct usb_driver ath6kl_usb_driver = {
static int ath6kl_usb_init(void)
{
usb_register(&ath6kl_usb_driver);
int ret;
ret = usb_register(&ath6kl_usb_driver);
if (ret) {
ath6kl_err("usb registration failed: %d\n", ret);
return ret;
}
return 0;
}
@ -1220,3 +1237,6 @@ MODULE_FIRMWARE(AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE);
MODULE_FIRMWARE(AR6004_HW_1_2_FIRMWARE_FILE);
MODULE_FIRMWARE(AR6004_HW_1_2_BOARD_DATA_FILE);
MODULE_FIRMWARE(AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE);
MODULE_FIRMWARE(AR6004_HW_1_3_FW_DIR "/" AR6004_HW_1_3_FIRMWARE_FILE);
MODULE_FIRMWARE(AR6004_HW_1_3_BOARD_DATA_FILE);
MODULE_FIRMWARE(AR6004_HW_1_3_DEFAULT_BOARD_DATA_FILE);

View File

@ -474,7 +474,7 @@ static int ath6kl_wmi_remain_on_chnl_event_rx(struct wmi *wmi, u8 *datap,
return -EINVAL;
}
id = vif->last_roc_id;
cfg80211_ready_on_channel(&vif->wdev, id, chan, NL80211_CHAN_NO_HT,
cfg80211_ready_on_channel(&vif->wdev, id, chan,
dur, GFP_ATOMIC);
return 0;
@ -513,8 +513,7 @@ static int ath6kl_wmi_cancel_remain_on_chnl_event_rx(struct wmi *wmi,
else
id = vif->last_roc_id; /* timeout on uncanceled r-o-c */
vif->last_cancel_roc_id = 0;
cfg80211_remain_on_channel_expired(&vif->wdev, id, chan,
NL80211_CHAN_NO_HT, GFP_ATOMIC);
cfg80211_remain_on_channel_expired(&vif->wdev, id, chan, GFP_ATOMIC);
return 0;
}
@ -936,8 +935,12 @@ static void ath6kl_wmi_regdomain_event(struct wmi *wmi, u8 *datap, int len)
regpair = ath6kl_get_regpair((u16) reg_code);
country = ath6kl_regd_find_country_by_rd((u16) reg_code);
ath6kl_dbg(ATH6KL_DBG_WMI, "Regpair used: 0x%0x\n",
regpair->regDmnEnum);
if (regpair)
ath6kl_dbg(ATH6KL_DBG_WMI, "Regpair used: 0x%0x\n",
regpair->regDmnEnum);
else
ath6kl_warn("Regpair not found reg_code 0x%0x\n",
reg_code);
}
if (country && wmi->parent_dev->wiphy_registered) {
@ -1116,7 +1119,7 @@ static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len,
* the timer would not ever fire if the scan interval is short
* enough.
*/
if (ar->state == ATH6KL_STATE_SCHED_SCAN &&
if (test_bit(SCHED_SCANNING, &vif->flags) &&
!timer_pending(&vif->sched_scan_timer)) {
mod_timer(&vif->sched_scan_timer, jiffies +
msecs_to_jiffies(ATH6KL_SCHED_SCAN_RESULT_DELAY));
@ -1170,6 +1173,9 @@ static int ath6kl_wmi_bitrate_reply_rx(struct wmi *wmi, u8 *datap, int len)
rate = RATE_AUTO;
} else {
index = reply->rate_index & 0x7f;
if (WARN_ON_ONCE(index > (RATE_MCS_7_40 + 1)))
return -EINVAL;
sgi = (reply->rate_index & 0x80) ? 1 : 0;
rate = wmi_rate_tbl[index][sgi];
}
@ -1531,6 +1537,68 @@ static int ath6kl_wmi_cac_event_rx(struct wmi *wmi, u8 *datap, int len,
return 0;
}
static int ath6kl_wmi_txe_notify_event_rx(struct wmi *wmi, u8 *datap, int len,
struct ath6kl_vif *vif)
{
struct wmi_txe_notify_event *ev;
u32 rate, pkts;
if (len < sizeof(*ev))
return -EINVAL;
if (vif->sme_state != SME_CONNECTED)
return -ENOTCONN;
ev = (struct wmi_txe_notify_event *) datap;
rate = le32_to_cpu(ev->rate);
pkts = le32_to_cpu(ev->pkts);
ath6kl_dbg(ATH6KL_DBG_WMI, "TXE notify event: peer %pM rate %d% pkts %d intvl %ds\n",
vif->bssid, rate, pkts, vif->txe_intvl);
cfg80211_cqm_txe_notify(vif->ndev, vif->bssid, pkts,
rate, vif->txe_intvl, GFP_KERNEL);
return 0;
}
int ath6kl_wmi_set_txe_notify(struct wmi *wmi, u8 idx,
u32 rate, u32 pkts, u32 intvl)
{
struct sk_buff *skb;
struct wmi_txe_notify_cmd *cmd;
skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
if (!skb)
return -ENOMEM;
cmd = (struct wmi_txe_notify_cmd *) skb->data;
cmd->rate = cpu_to_le32(rate);
cmd->pkts = cpu_to_le32(pkts);
cmd->intvl = cpu_to_le32(intvl);
return ath6kl_wmi_cmd_send(wmi, idx, skb, WMI_SET_TXE_NOTIFY_CMDID,
NO_SYNC_WMIFLAG);
}
int ath6kl_wmi_set_rssi_filter_cmd(struct wmi *wmi, u8 if_idx, s8 rssi)
{
struct sk_buff *skb;
struct wmi_set_rssi_filter_cmd *cmd;
int ret;
skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
if (!skb)
return -ENOMEM;
cmd = (struct wmi_set_rssi_filter_cmd *) skb->data;
cmd->rssi = rssi;
ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_RSSI_FILTER_CMDID,
NO_SYNC_WMIFLAG);
return ret;
}
static int ath6kl_wmi_send_snr_threshold_params(struct wmi *wmi,
struct wmi_snr_threshold_params_cmd *snr_cmd)
{
@ -1677,8 +1745,11 @@ int ath6kl_wmi_cmd_send(struct wmi *wmi, u8 if_idx, struct sk_buff *skb,
int ret;
u16 info1;
if (WARN_ON(skb == NULL || (if_idx > (wmi->parent_dev->vif_max - 1))))
if (WARN_ON(skb == NULL ||
(if_idx > (wmi->parent_dev->vif_max - 1)))) {
dev_kfree_skb(skb);
return -EINVAL;
}
ath6kl_dbg(ATH6KL_DBG_WMI, "wmi tx id %d len %d flag %d\n",
cmd_id, skb->len, sync_flag);
@ -1833,6 +1904,59 @@ int ath6kl_wmi_disconnect_cmd(struct wmi *wmi, u8 if_idx)
return ret;
}
/* ath6kl_wmi_start_scan_cmd is to be deprecated. Use
* ath6kl_wmi_begin_scan_cmd instead. The new function supports P2P
* mgmt operations using station interface.
*/
static int ath6kl_wmi_startscan_cmd(struct wmi *wmi, u8 if_idx,
enum wmi_scan_type scan_type,
u32 force_fgscan, u32 is_legacy,
u32 home_dwell_time,
u32 force_scan_interval,
s8 num_chan, u16 *ch_list)
{
struct sk_buff *skb;
struct wmi_start_scan_cmd *sc;
s8 size;
int i, ret;
size = sizeof(struct wmi_start_scan_cmd);
if ((scan_type != WMI_LONG_SCAN) && (scan_type != WMI_SHORT_SCAN))
return -EINVAL;
if (num_chan > WMI_MAX_CHANNELS)
return -EINVAL;
if (num_chan)
size += sizeof(u16) * (num_chan - 1);
skb = ath6kl_wmi_get_new_buf(size);
if (!skb)
return -ENOMEM;
sc = (struct wmi_start_scan_cmd *) skb->data;
sc->scan_type = scan_type;
sc->force_fg_scan = cpu_to_le32(force_fgscan);
sc->is_legacy = cpu_to_le32(is_legacy);
sc->home_dwell_time = cpu_to_le32(home_dwell_time);
sc->force_scan_intvl = cpu_to_le32(force_scan_interval);
sc->num_ch = num_chan;
for (i = 0; i < num_chan; i++)
sc->ch_list[i] = cpu_to_le16(ch_list[i]);
ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_START_SCAN_CMDID,
NO_SYNC_WMIFLAG);
return ret;
}
/*
* beginscan supports (compared to old startscan) P2P mgmt operations using
* station interface, send additional information like supported rates to
* advertise and xmit rates for probe requests
*/
int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx,
enum wmi_scan_type scan_type,
u32 force_fgscan, u32 is_legacy,
@ -1848,6 +1972,15 @@ int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx,
int num_rates;
u32 ratemask;
if (!test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX,
ar->fw_capabilities)) {
return ath6kl_wmi_startscan_cmd(wmi, if_idx,
scan_type, force_fgscan,
is_legacy, home_dwell_time,
force_scan_interval,
num_chan, ch_list);
}
size = sizeof(struct wmi_begin_scan_cmd);
if ((scan_type != WMI_LONG_SCAN) && (scan_type != WMI_SHORT_SCAN))
@ -1900,50 +2033,24 @@ int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx,
return ret;
}
/* ath6kl_wmi_start_scan_cmd is to be deprecated. Use
* ath6kl_wmi_begin_scan_cmd instead. The new function supports P2P
* mgmt operations using station interface.
*/
int ath6kl_wmi_startscan_cmd(struct wmi *wmi, u8 if_idx,
enum wmi_scan_type scan_type,
u32 force_fgscan, u32 is_legacy,
u32 home_dwell_time, u32 force_scan_interval,
s8 num_chan, u16 *ch_list)
int ath6kl_wmi_enable_sched_scan_cmd(struct wmi *wmi, u8 if_idx, bool enable)
{
struct sk_buff *skb;
struct wmi_start_scan_cmd *sc;
s8 size;
int i, ret;
struct wmi_enable_sched_scan_cmd *sc;
int ret;
size = sizeof(struct wmi_start_scan_cmd);
if ((scan_type != WMI_LONG_SCAN) && (scan_type != WMI_SHORT_SCAN))
return -EINVAL;
if (num_chan > WMI_MAX_CHANNELS)
return -EINVAL;
if (num_chan)
size += sizeof(u16) * (num_chan - 1);
skb = ath6kl_wmi_get_new_buf(size);
skb = ath6kl_wmi_get_new_buf(sizeof(*sc));
if (!skb)
return -ENOMEM;
sc = (struct wmi_start_scan_cmd *) skb->data;
sc->scan_type = scan_type;
sc->force_fg_scan = cpu_to_le32(force_fgscan);
sc->is_legacy = cpu_to_le32(is_legacy);
sc->home_dwell_time = cpu_to_le32(home_dwell_time);
sc->force_scan_intvl = cpu_to_le32(force_scan_interval);
sc->num_ch = num_chan;
ath6kl_dbg(ATH6KL_DBG_WMI, "%s scheduled scan on vif %d\n",
enable ? "enabling" : "disabling", if_idx);
sc = (struct wmi_enable_sched_scan_cmd *) skb->data;
sc->enable = enable ? 1 : 0;
for (i = 0; i < num_chan; i++)
sc->ch_list[i] = cpu_to_le16(ch_list[i]);
ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_START_SCAN_CMDID,
ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb,
WMI_ENABLE_SCHED_SCAN_CMDID,
NO_SYNC_WMIFLAG);
return ret;
}
@ -2275,8 +2382,10 @@ static int ath6kl_wmi_data_sync_send(struct wmi *wmi, struct sk_buff *skb,
struct wmi_data_hdr *data_hdr;
int ret;
if (WARN_ON(skb == NULL || ep_id == wmi->ep_id))
if (WARN_ON(skb == NULL || ep_id == wmi->ep_id)) {
dev_kfree_skb(skb);
return -EINVAL;
}
skb_push(skb, sizeof(struct wmi_data_hdr));
@ -2313,10 +2422,8 @@ static int ath6kl_wmi_sync_point(struct wmi *wmi, u8 if_idx)
spin_unlock_bh(&wmi->lock);
skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
if (!skb) {
ret = -ENOMEM;
goto free_skb;
}
if (!skb)
return -ENOMEM;
cmd = (struct wmi_sync_cmd *) skb->data;
@ -2339,7 +2446,7 @@ static int ath6kl_wmi_sync_point(struct wmi *wmi, u8 if_idx)
* then do not send the Synchronize cmd on the control ep
*/
if (ret)
goto free_skb;
goto free_cmd_skb;
/*
* Send sync cmd followed by sync data messages on all
@ -2349,15 +2456,12 @@ static int ath6kl_wmi_sync_point(struct wmi *wmi, u8 if_idx)
NO_SYNC_WMIFLAG);
if (ret)
goto free_skb;
/* cmd buffer sent, we no longer own it */
skb = NULL;
goto free_data_skb;
for (index = 0; index < num_pri_streams; index++) {
if (WARN_ON(!data_sync_bufs[index].skb))
break;
goto free_data_skb;
ep_id = ath6kl_ac2_endpoint_id(wmi->parent_dev,
data_sync_bufs[index].
@ -2366,17 +2470,20 @@ static int ath6kl_wmi_sync_point(struct wmi *wmi, u8 if_idx)
ath6kl_wmi_data_sync_send(wmi, data_sync_bufs[index].skb,
ep_id, if_idx);
if (ret)
break;
data_sync_bufs[index].skb = NULL;
if (ret)
goto free_data_skb;
}
free_skb:
return 0;
free_cmd_skb:
/* free up any resources left over (possibly due to an error) */
if (skb)
dev_kfree_skb(skb);
free_data_skb:
for (index = 0; index < num_pri_streams; index++) {
if (data_sync_bufs[index].skb != NULL) {
dev_kfree_skb((struct sk_buff *)data_sync_bufs[index].
@ -2618,11 +2725,13 @@ static int ath6kl_set_bitrate_mask64(struct wmi *wmi, u8 if_idx,
{
struct sk_buff *skb;
int ret, mode, band;
u64 mcsrate, ratemask[IEEE80211_NUM_BANDS];
u64 mcsrate, ratemask[ATH6KL_NUM_BANDS];
struct wmi_set_tx_select_rates64_cmd *cmd;
memset(&ratemask, 0, sizeof(ratemask));
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
/* only check 2.4 and 5 GHz bands, skip the rest */
for (band = 0; band <= IEEE80211_BAND_5GHZ; band++) {
/* copy legacy rate mask */
ratemask[band] = mask->control[band].legacy;
if (band == IEEE80211_BAND_5GHZ)
@ -2668,11 +2777,13 @@ static int ath6kl_set_bitrate_mask32(struct wmi *wmi, u8 if_idx,
{
struct sk_buff *skb;
int ret, mode, band;
u32 mcsrate, ratemask[IEEE80211_NUM_BANDS];
u32 mcsrate, ratemask[ATH6KL_NUM_BANDS];
struct wmi_set_tx_select_rates32_cmd *cmd;
memset(&ratemask, 0, sizeof(ratemask));
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
/* only check 2.4 and 5 GHz bands, skip the rest */
for (band = 0; band <= IEEE80211_BAND_5GHZ; band++) {
/* copy legacy rate mask */
ratemask[band] = mask->control[band].legacy;
if (band == IEEE80211_BAND_5GHZ)
@ -2716,7 +2827,7 @@ int ath6kl_wmi_set_bitrate_mask(struct wmi *wmi, u8 if_idx,
{
struct ath6kl *ar = wmi->parent_dev;
if (ar->hw.flags & ATH6KL_HW_FLAG_64BIT_RATES)
if (ar->hw.flags & ATH6KL_HW_64BIT_RATES)
return ath6kl_set_bitrate_mask64(wmi, if_idx, mask);
else
return ath6kl_set_bitrate_mask32(wmi, if_idx, mask);
@ -3139,12 +3250,40 @@ int ath6kl_wmi_sta_bmiss_enhance_cmd(struct wmi *wmi, u8 if_idx, bool enhance)
return ret;
}
int ath6kl_wmi_set_regdomain_cmd(struct wmi *wmi, const char *alpha2)
{
struct sk_buff *skb;
struct wmi_set_regdomain_cmd *cmd;
skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
if (!skb)
return -ENOMEM;
cmd = (struct wmi_set_regdomain_cmd *) skb->data;
memcpy(cmd->iso_name, alpha2, 2);
return ath6kl_wmi_cmd_send(wmi, 0, skb,
WMI_SET_REGDOMAIN_CMDID,
NO_SYNC_WMIFLAG);
}
s32 ath6kl_wmi_get_rate(s8 rate_index)
{
u8 sgi = 0;
if (rate_index == RATE_AUTO)
return 0;
return wmi_rate_tbl[(u32) rate_index][0];
/* SGI is stored as the MSB of the rate_index */
if (rate_index & RATE_INDEX_MSB) {
rate_index &= RATE_INDEX_WITHOUT_SGI_MASK;
sgi = 1;
}
if (WARN_ON(rate_index > RATE_MCS_7_40))
rate_index = RATE_MCS_7_40;
return wmi_rate_tbl[(u32) rate_index][sgi];
}
static int ath6kl_wmi_get_pmkid_list_event_rx(struct wmi *wmi, u8 *datap,
@ -3634,6 +3773,19 @@ int ath6kl_wmi_set_inact_period(struct wmi *wmi, u8 if_idx, int inact_timeout)
NO_SYNC_WMIFLAG);
}
static void ath6kl_wmi_hb_challenge_resp_event(struct wmi *wmi, u8 *datap,
int len)
{
struct wmix_hb_challenge_resp_cmd *cmd;
if (len < sizeof(struct wmix_hb_challenge_resp_cmd))
return;
cmd = (struct wmix_hb_challenge_resp_cmd *) datap;
ath6kl_recovery_hb_event(wmi->parent_dev,
le32_to_cpu(cmd->cookie));
}
static int ath6kl_wmi_control_rx_xtnd(struct wmi *wmi, struct sk_buff *skb)
{
struct wmix_cmd_hdr *cmd;
@ -3658,6 +3810,7 @@ static int ath6kl_wmi_control_rx_xtnd(struct wmi *wmi, struct sk_buff *skb)
switch (id) {
case WMIX_HB_CHALLENGE_RESP_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "wmi event hb challenge resp\n");
ath6kl_wmi_hb_challenge_resp_event(wmi, datap, len);
break;
case WMIX_DBGLOG_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "wmi event dbglog len %d\n", len);
@ -3750,6 +3903,9 @@ static int ath6kl_wmi_proc_events_vif(struct wmi *wmi, u16 if_idx, u16 cmd_id,
case WMI_RX_ACTION_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_ACTION_EVENTID\n");
return ath6kl_wmi_rx_action_event_rx(wmi, datap, len, vif);
case WMI_TXE_NOTIFY_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TXE_NOTIFY_EVENTID\n");
return ath6kl_wmi_txe_notify_event_rx(wmi, datap, len, vif);
default:
ath6kl_dbg(ATH6KL_DBG_WMI, "unknown cmd id 0x%x\n", cmd_id);
return -EINVAL;

View File

@ -48,7 +48,7 @@
#define A_BAND_24GHZ 0
#define A_BAND_5GHZ 1
#define A_NUM_BANDS 2
#define ATH6KL_NUM_BANDS 2
/* in ms */
#define WMI_IMPLICIT_PSTREAM_INACTIVITY_INT 5000
@ -628,6 +628,20 @@ enum wmi_cmd_id {
WMI_SET_MCASTRATE,
WMI_STA_BMISS_ENHANCE_CMDID,
WMI_SET_REGDOMAIN_CMDID,
WMI_SET_RSSI_FILTER_CMDID,
WMI_SET_KEEP_ALIVE_EXT,
WMI_VOICE_DETECTION_ENABLE_CMDID,
WMI_SET_TXE_NOTIFY_CMDID,
WMI_SET_RECOVERY_TEST_PARAMETER_CMDID, /*0xf094*/
WMI_ENABLE_SCHED_SCAN_CMDID,
};
enum wmi_mgmt_frame_type {
@ -843,7 +857,7 @@ struct wmi_begin_scan_cmd {
u8 scan_type;
/* Supported rates to advertise in the probe request frames */
struct wmi_supp_rates supp_rates[IEEE80211_NUM_BANDS];
struct wmi_supp_rates supp_rates[ATH6KL_NUM_BANDS];
/* how many channels follow */
u8 num_ch;
@ -941,6 +955,11 @@ struct wmi_scan_params_cmd {
__le32 max_dfsch_act_time;
} __packed;
/* WMI_ENABLE_SCHED_SCAN_CMDID */
struct wmi_enable_sched_scan_cmd {
u8 enable;
} __packed;
/* WMI_SET_BSS_FILTER_CMDID */
enum wmi_bss_filter {
/* no beacons forwarded */
@ -1032,6 +1051,11 @@ struct wmi_sta_bmiss_enhance_cmd {
u8 enable;
} __packed;
struct wmi_set_regdomain_cmd {
u8 length;
u8 iso_name[2];
} __packed;
/* WMI_SET_POWER_MODE_CMDID */
enum wmi_power_mode {
REC_POWER = 0x01,
@ -1276,6 +1300,11 @@ struct wmi_snr_threshold_params_cmd {
u8 reserved[3];
} __packed;
/* Don't report BSSs with signal (RSSI) below this threshold */
struct wmi_set_rssi_filter_cmd {
s8 rssi;
} __packed;
enum wmi_preamble_policy {
WMI_IGNORE_BARKER_IN_ERP = 0,
WMI_FOLLOW_BARKER_IN_ERP,
@ -1455,6 +1484,20 @@ enum wmi_event_id {
WMI_P2P_CAPABILITIES_EVENTID,
WMI_RX_ACTION_EVENTID,
WMI_P2P_INFO_EVENTID,
/* WPS Events */
WMI_WPS_GET_STATUS_EVENTID,
WMI_WPS_PROFILE_EVENTID,
/* more P2P events */
WMI_NOA_INFO_EVENTID,
WMI_OPPPS_INFO_EVENTID,
WMI_PORT_STATUS_EVENTID,
/* 802.11w */
WMI_GET_RSN_CAP_EVENTID,
WMI_TXE_NOTIFY_EVENTID,
};
struct wmi_ready_event_2 {
@ -1749,6 +1792,9 @@ struct rx_stats {
a_sle32 ucast_rate;
} __packed;
#define RATE_INDEX_WITHOUT_SGI_MASK 0x7f
#define RATE_INDEX_MSB 0x80
struct tkip_ccmp_stats {
__le32 tkip_local_mic_fail;
__le32 tkip_cnter_measures_invoked;
@ -2019,7 +2065,6 @@ struct wmi_set_ie_cmd {
#define WOW_MAX_FILTERS_PER_LIST 4
#define WOW_PATTERN_SIZE 64
#define WOW_MASK_SIZE 64
#define MAC_MAX_FILTERS_PER_LIST 4
@ -2028,7 +2073,7 @@ struct wow_filter {
u8 wow_filter_id;
u8 wow_filter_size;
u8 wow_filter_offset;
u8 wow_filter_mask[WOW_MASK_SIZE];
u8 wow_filter_mask[WOW_PATTERN_SIZE];
u8 wow_filter_pattern[WOW_PATTERN_SIZE];
} __packed;
@ -2087,6 +2132,19 @@ struct wmi_del_wow_pattern_cmd {
__le16 filter_id;
} __packed;
/* WMI_SET_TXE_NOTIFY_CMDID */
struct wmi_txe_notify_cmd {
__le32 rate;
__le32 pkts;
__le32 intvl;
} __packed;
/* WMI_TXE_NOTIFY_EVENTID */
struct wmi_txe_notify_event {
__le32 rate;
__le32 pkts;
} __packed;
/* WMI_SET_AKMP_PARAMS_CMD */
struct wmi_pmkid {
@ -2505,11 +2563,6 @@ int ath6kl_wmi_connect_cmd(struct wmi *wmi, u8 if_idx,
int ath6kl_wmi_reconnect_cmd(struct wmi *wmi, u8 if_idx, u8 *bssid,
u16 channel);
int ath6kl_wmi_disconnect_cmd(struct wmi *wmi, u8 if_idx);
int ath6kl_wmi_startscan_cmd(struct wmi *wmi, u8 if_idx,
enum wmi_scan_type scan_type,
u32 force_fgscan, u32 is_legacy,
u32 home_dwell_time, u32 force_scan_interval,
s8 num_chan, u16 *ch_list);
int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx,
enum wmi_scan_type scan_type,
@ -2517,6 +2570,7 @@ int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx,
u32 home_dwell_time, u32 force_scan_interval,
s8 num_chan, u16 *ch_list, u32 no_cck,
u32 *rates);
int ath6kl_wmi_enable_sched_scan_cmd(struct wmi *wmi, u8 if_idx, bool enable);
int ath6kl_wmi_scanparams_cmd(struct wmi *wmi, u8 if_idx, u16 fg_start_sec,
u16 fg_end_sec, u16 bg_sec,
@ -2592,6 +2646,7 @@ int ath6kl_wmi_add_wow_pattern_cmd(struct wmi *wmi, u8 if_idx,
const u8 *mask);
int ath6kl_wmi_del_wow_pattern_cmd(struct wmi *wmi, u8 if_idx,
u16 list_id, u16 filter_id);
int ath6kl_wmi_set_rssi_filter_cmd(struct wmi *wmi, u8 if_idx, s8 rssi);
int ath6kl_wmi_set_roam_lrssi_cmd(struct wmi *wmi, u8 lrssi);
int ath6kl_wmi_ap_set_dtim_cmd(struct wmi *wmi, u8 if_idx, u32 dtim_period);
int ath6kl_wmi_force_roam_cmd(struct wmi *wmi, const u8 *bssid);
@ -2600,6 +2655,9 @@ int ath6kl_wmi_mcast_filter_cmd(struct wmi *wmi, u8 if_idx, bool mc_all_on);
int ath6kl_wmi_add_del_mcast_filter_cmd(struct wmi *wmi, u8 if_idx,
u8 *filter, bool add_filter);
int ath6kl_wmi_sta_bmiss_enhance_cmd(struct wmi *wmi, u8 if_idx, bool enable);
int ath6kl_wmi_set_txe_notify(struct wmi *wmi, u8 idx,
u32 rate, u32 pkts, u32 intvl);
int ath6kl_wmi_set_regdomain_cmd(struct wmi *wmi, const char *alpha2);
/* AP mode uAPSD */
int ath6kl_wmi_ap_set_apsd(struct wmi *wmi, u8 if_idx, u8 enable);
@ -2658,6 +2716,8 @@ int ath6kl_wmi_set_inact_period(struct wmi *wmi, u8 if_idx, int inact_timeout);
void ath6kl_wmi_sscan_timer(unsigned long ptr);
int ath6kl_wmi_get_challenge_resp_cmd(struct wmi *wmi, u32 cookie, u32 source);
struct ath6kl_vif *ath6kl_get_vif_by_index(struct ath6kl *ar, u8 if_idx);
void *ath6kl_wmi_init(struct ath6kl *devt);
void ath6kl_wmi_shutdown(struct wmi *wmi);

View File

@ -891,6 +891,74 @@ static void ar9003_hw_tx_iq_cal_reload(struct ath_hw *ah)
AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x1);
}
static void ar9003_hw_manual_peak_cal(struct ath_hw *ah, u8 chain, bool is_2g)
{
int offset[8], total = 0, test;
int agc_out, i;
REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain),
AR_PHY_65NM_RXRF_GAINSTAGES_RX_OVERRIDE, 0x1);
REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain),
AR_PHY_65NM_RXRF_GAINSTAGES_LNAON_CALDC, 0x0);
if (is_2g)
REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain),
AR_PHY_65NM_RXRF_GAINSTAGES_LNA2G_GAIN_OVR, 0x0);
else
REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain),
AR_PHY_65NM_RXRF_GAINSTAGES_LNA5G_GAIN_OVR, 0x0);
REG_RMW_FIELD(ah, AR_PHY_65NM_RXTX2(chain),
AR_PHY_65NM_RXTX2_RXON_OVR, 0x1);
REG_RMW_FIELD(ah, AR_PHY_65NM_RXTX2(chain),
AR_PHY_65NM_RXTX2_RXON, 0x0);
REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
AR_PHY_65NM_RXRF_AGC_AGC_OVERRIDE, 0x1);
REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
AR_PHY_65NM_RXRF_AGC_AGC_ON_OVR, 0x1);
REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
AR_PHY_65NM_RXRF_AGC_AGC_CAL_OVR, 0x1);
if (is_2g)
REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
AR_PHY_65NM_RXRF_AGC_AGC2G_DBDAC_OVR, 0x0);
else
REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
AR_PHY_65NM_RXRF_AGC_AGC5G_DBDAC_OVR, 0x0);
for (i = 6; i > 0; i--) {
offset[i] = BIT(i - 1);
test = total + offset[i];
if (is_2g)
REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR,
test);
else
REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR,
test);
udelay(100);
agc_out = REG_READ_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
AR_PHY_65NM_RXRF_AGC_AGC_OUT);
offset[i] = (agc_out) ? 0 : 1;
total += (offset[i] << (i - 1));
}
if (is_2g)
REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR, total);
else
REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR, total);
REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain),
AR_PHY_65NM_RXRF_GAINSTAGES_RX_OVERRIDE, 0);
REG_RMW_FIELD(ah, AR_PHY_65NM_RXTX2(chain),
AR_PHY_65NM_RXTX2_RXON_OVR, 0);
REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
AR_PHY_65NM_RXRF_AGC_AGC_CAL_OVR, 0);
}
static bool ar9003_hw_init_cal(struct ath_hw *ah,
struct ath9k_channel *chan)
{
@ -989,6 +1057,14 @@ skip_tx_iqcal:
status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
AR_PHY_AGC_CONTROL_CAL,
0, AH_WAIT_TIMEOUT);
if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) {
for (i = 0; i < AR9300_MAX_CHAINS; i++) {
if (!(ah->rxchainmask & (1 << i)))
continue;
ar9003_hw_manual_peak_cal(ah, i,
IS_CHAN_2GHZ(chan));
}
}
}
if (ath9k_hw_mci_is_enabled(ah) && IS_CHAN_2GHZ(chan) && run_agc_cal)

View File

@ -35,12 +35,6 @@
*/
static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
{
#define AR9462_BB_CTX_COEFJ(x) \
ar9462_##x##_baseband_core_txfir_coeff_japan_2484
#define AR9462_BBC_TXIFR_COEFFJ \
ar9462_2p0_baseband_core_txfir_coeff_japan_2484
if (AR_SREV_9330_11(ah)) {
/* mac */
INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE],
@ -70,6 +64,10 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9331_modes_lowest_ob_db_tx_gain_1p1);
/* Japan 2484 Mhz CCK */
INIT_INI_ARRAY(&ah->iniCckfirJapan2484,
ar9331_1p1_baseband_core_txfir_coeff_japan_2484);
/* additional clock settings */
if (ah->is_clk_25mhz)
INIT_INI_ARRAY(&ah->iniAdditional,
@ -106,6 +104,10 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9331_modes_lowest_ob_db_tx_gain_1p2);
/* Japan 2484 Mhz CCK */
INIT_INI_ARRAY(&ah->iniCckfirJapan2484,
ar9331_1p2_baseband_core_txfir_coeff_japan_2484);
/* additional clock settings */
if (ah->is_clk_25mhz)
INIT_INI_ARRAY(&ah->iniAdditional,
@ -180,6 +182,10 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9485_modes_lowest_ob_db_tx_gain_1_1);
/* Japan 2484 Mhz CCK */
INIT_INI_ARRAY(&ah->iniCckfirJapan2484,
ar9485_1_1_baseband_core_txfir_coeff_japan_2484);
/* Load PCIE SERDES settings from INI */
/* Awake Setting */
@ -229,9 +235,7 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
ar9462_modes_fast_clock_2p0);
INIT_INI_ARRAY(&ah->iniCckfirJapan2484,
AR9462_BB_CTX_COEFJ(2p0));
INIT_INI_ARRAY(&ah->ini_japan2484, AR9462_BBC_TXIFR_COEFFJ);
ar9462_2p0_baseband_core_txfir_coeff_japan_2484);
} else if (AR_SREV_9550(ah)) {
/* mac */
INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE],

View File

@ -714,7 +714,6 @@ bool ar9003_mci_start_reset(struct ath_hw *ah, struct ath9k_channel *chan)
return true;
}
EXPORT_SYMBOL(ar9003_mci_start_reset);
int ar9003_mci_end_reset(struct ath_hw *ah, struct ath9k_channel *chan,
struct ath9k_hw_cal_data *caldata)

View File

@ -784,7 +784,7 @@ static int ar9003_hw_process_ini(struct ath_hw *ah,
REG_WRITE_ARRAY(&ah->iniAdditional, 1, regWrites);
if (chan->channel == 2484)
ar9003_hw_prog_ini(ah, &ah->ini_japan2484, 1);
ar9003_hw_prog_ini(ah, &ah->iniCckfirJapan2484, 1);
if (AR_SREV_9462(ah) || AR_SREV_9565(ah))
REG_WRITE(ah, AR_GLB_SWREG_DISCONT_MODE,

View File

@ -698,13 +698,6 @@
#define AR_PHY_65NM_CH0_THERM_SAR_ADC_OUT 0x0000ff00
#define AR_PHY_65NM_CH0_THERM_SAR_ADC_OUT_S 8
#define AR_PHY_65NM_CH0_RXTX1 0x16100
#define AR_PHY_65NM_CH0_RXTX2 0x16104
#define AR_PHY_65NM_CH1_RXTX1 0x16500
#define AR_PHY_65NM_CH1_RXTX2 0x16504
#define AR_PHY_65NM_CH2_RXTX1 0x16900
#define AR_PHY_65NM_CH2_RXTX2 0x16904
#define AR_CH0_TOP2 (AR_SREV_9300(ah) ? 0x1628c : \
(AR_SREV_9462(ah) ? 0x16290 : 0x16284))
#define AR_CH0_TOP2_XPABIASLVL 0xf000
@ -1286,4 +1279,43 @@
#define AR_BTCOEX_WL_LNADIV_BT_INACTIVE_THRESHOLD 0xFC000000
#define AR_BTCOEX_WL_LNADIV_BT_INACTIVE_THRESHOLD_S 26
/* Manual Peak detector calibration */
#define AR_PHY_65NM_BASE 0x16000
#define AR_PHY_65NM_RXRF_GAINSTAGES(i) (AR_PHY_65NM_BASE + \
(i * 0x400) + 0x8)
#define AR_PHY_65NM_RXRF_GAINSTAGES_RX_OVERRIDE 0x80000000
#define AR_PHY_65NM_RXRF_GAINSTAGES_RX_OVERRIDE_S 31
#define AR_PHY_65NM_RXRF_GAINSTAGES_LNAON_CALDC 0x00000002
#define AR_PHY_65NM_RXRF_GAINSTAGES_LNAON_CALDC_S 1
#define AR_PHY_65NM_RXRF_GAINSTAGES_LNA2G_GAIN_OVR 0x70000000
#define AR_PHY_65NM_RXRF_GAINSTAGES_LNA2G_GAIN_OVR_S 28
#define AR_PHY_65NM_RXRF_GAINSTAGES_LNA5G_GAIN_OVR 0x03800000
#define AR_PHY_65NM_RXRF_GAINSTAGES_LNA5G_GAIN_OVR_S 23
#define AR_PHY_65NM_RXTX2(i) (AR_PHY_65NM_BASE + \
(i * 0x400) + 0x104)
#define AR_PHY_65NM_RXTX2_RXON_OVR 0x00001000
#define AR_PHY_65NM_RXTX2_RXON_OVR_S 12
#define AR_PHY_65NM_RXTX2_RXON 0x00000800
#define AR_PHY_65NM_RXTX2_RXON_S 11
#define AR_PHY_65NM_RXRF_AGC(i) (AR_PHY_65NM_BASE + \
(i * 0x400) + 0xc)
#define AR_PHY_65NM_RXRF_AGC_AGC_OVERRIDE 0x80000000
#define AR_PHY_65NM_RXRF_AGC_AGC_OVERRIDE_S 31
#define AR_PHY_65NM_RXRF_AGC_AGC_ON_OVR 0x40000000
#define AR_PHY_65NM_RXRF_AGC_AGC_ON_OVR_S 30
#define AR_PHY_65NM_RXRF_AGC_AGC_CAL_OVR 0x20000000
#define AR_PHY_65NM_RXRF_AGC_AGC_CAL_OVR_S 29
#define AR_PHY_65NM_RXRF_AGC_AGC2G_DBDAC_OVR 0x1E000000
#define AR_PHY_65NM_RXRF_AGC_AGC2G_DBDAC_OVR_S 25
#define AR_PHY_65NM_RXRF_AGC_AGC5G_DBDAC_OVR 0x00078000
#define AR_PHY_65NM_RXRF_AGC_AGC5G_DBDAC_OVR_S 15
#define AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR 0x01F80000
#define AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR_S 19
#define AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR 0x00007e00
#define AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR_S 9
#define AR_PHY_65NM_RXRF_AGC_AGC_OUT 0x00000004
#define AR_PHY_65NM_RXRF_AGC_AGC_OUT_S 2
#endif /* AR9003_PHY_H */

View File

@ -78,7 +78,7 @@ static const u32 ar9462_2p0_baseband_postamble[][5] = {
{0x0000a284, 0x00000000, 0x00000000, 0x00000150, 0x00000150},
{0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110},
{0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222},
{0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18},
{0x0000a2c4, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18},
{0x0000a2d0, 0x00041981, 0x00041981, 0x00041981, 0x00041982},
{0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b},
{0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000},

View File

@ -18,7 +18,7 @@
#ifndef INITVALS_9485_H
#define INITVALS_9485_H
/* AR9485 1.0 */
/* AR9485 1.1 */
#define ar9485_1_1_mac_postamble ar9300_2p2_mac_postamble
@ -31,6 +31,11 @@ static const u32 ar9485_1_1_pcie_phy_pll_on_clkreq_disable_L1[][2] = {
static const u32 ar9485Common_wo_xlna_rx_gain_1_1[][2] = {
/* Addr allmodes */
{0x00009e00, 0x037216a0},
{0x00009e04, 0x00182020},
{0x00009e18, 0x00000000},
{0x00009e2c, 0x00004121},
{0x00009e44, 0x02282324},
{0x0000a000, 0x00060005},
{0x0000a004, 0x00810080},
{0x0000a008, 0x00830082},
@ -164,6 +169,11 @@ static const u32 ar9485Common_wo_xlna_rx_gain_1_1[][2] = {
static const u32 ar9485Modes_high_power_tx_gain_1_1[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
{0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002},
{0x0000a2d8, 0xf999a83a, 0xf999a83a, 0x7999a83a, 0x7999a83a},
{0x0000a2dc, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552},
{0x0000a2e0, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552},
{0x0000a2e4, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552},
{0x0000a2e8, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552},
{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8},
{0x0000a458, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000},
@ -198,6 +208,22 @@ static const u32 ar9485Modes_high_power_tx_gain_1_1[][5] = {
{0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
{0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
{0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
{0x0000a580, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a584, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a588, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a58c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a590, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a594, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a598, 0x00000000, 0x00000000, 0x01404501, 0x01404501},
{0x0000a59c, 0x00000000, 0x00000000, 0x02808a02, 0x02808a02},
{0x0000a5a0, 0x00000000, 0x00000000, 0x02808a02, 0x02808a02},
{0x0000a5a4, 0x00000000, 0x00000000, 0x02808803, 0x02808803},
{0x0000a5a8, 0x00000000, 0x00000000, 0x04c14b04, 0x04c14b04},
{0x0000a5ac, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305},
{0x0000a5b0, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305},
{0x0000a5b4, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305},
{0x0000a5b8, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305},
{0x0000a5bc, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305},
{0x0000b500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b504, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b508, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
@ -234,9 +260,193 @@ static const u32 ar9485Modes_high_power_tx_gain_1_1[][5] = {
{0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260},
};
#define ar9485Modes_high_ob_db_tx_gain_1_1 ar9485Modes_high_power_tx_gain_1_1
static const u32 ar9485Modes_high_ob_db_tx_gain_1_1[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
{0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002},
{0x0000a2d8, 0xf999a83a, 0xf999a83a, 0x7999a83a, 0x7999a83a},
{0x0000a2dc, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552},
{0x0000a2e0, 0x00000000, 0x00000000, 0xffc63a84, 0xffc63a84},
{0x0000a2e4, 0x00000000, 0x00000000, 0xfe0fc000, 0xfe0fc000},
{0x0000a2e8, 0x00000000, 0x00000000, 0xfff00000, 0xfff00000},
{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8},
{0x0000a458, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000},
{0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002},
{0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004},
{0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200},
{0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202},
{0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400},
{0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402},
{0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404},
{0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603},
{0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605},
{0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03},
{0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04},
{0x0000a530, 0x48023ec6, 0x48023ec6, 0x34000e20, 0x34000e20},
{0x0000a534, 0x4d023f01, 0x4d023f01, 0x35000e21, 0x35000e21},
{0x0000a538, 0x53023f4b, 0x53023f4b, 0x43000e62, 0x43000e62},
{0x0000a53c, 0x5a027f09, 0x5a027f09, 0x45000e63, 0x45000e63},
{0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x49000e65, 0x49000e65},
{0x0000a544, 0x6502feca, 0x6502feca, 0x4b000e66, 0x4b000e66},
{0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x4d001645, 0x4d001645},
{0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865},
{0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86},
{0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9},
{0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb},
{0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb},
{0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb},
{0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb},
{0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
{0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
{0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
{0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
{0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
{0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
{0x0000a580, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a584, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a588, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a58c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a590, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a594, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a598, 0x00000000, 0x00000000, 0x01404501, 0x01404501},
{0x0000a59c, 0x00000000, 0x00000000, 0x02808a02, 0x02808a02},
{0x0000a5a0, 0x00000000, 0x00000000, 0x02808a02, 0x02808a02},
{0x0000a5a4, 0x00000000, 0x00000000, 0x02808803, 0x02808803},
{0x0000a5a8, 0x00000000, 0x00000000, 0x04c14b04, 0x04c14b04},
{0x0000a5ac, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305},
{0x0000a5b0, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305},
{0x0000a5b4, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305},
{0x0000a5b8, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305},
{0x0000a5bc, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305},
{0x0000b500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b504, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b508, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b50c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b510, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b514, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b518, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b51c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b520, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b524, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b528, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b52c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b530, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b534, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b538, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b53c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b540, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b544, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b548, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b54c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b550, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b554, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b558, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b55c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b560, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b564, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b568, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b56c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b570, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b574, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b578, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b57c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x00016044, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db},
{0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260},
};
#define ar9485Modes_low_ob_db_tx_gain_1_1 ar9485Modes_high_ob_db_tx_gain_1_1
static const u32 ar9485Modes_low_ob_db_tx_gain_1_1[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
{0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002},
{0x0000a2d8, 0xf999a83a, 0xf999a83a, 0x7999a83a, 0x7999a83a},
{0x0000a2dc, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552},
{0x0000a2e0, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552},
{0x0000a2e4, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552},
{0x0000a2e8, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552},
{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8},
{0x0000a458, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000},
{0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002},
{0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004},
{0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200},
{0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202},
{0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400},
{0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402},
{0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404},
{0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603},
{0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605},
{0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03},
{0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04},
{0x0000a530, 0x48023ec6, 0x48023ec6, 0x34000e20, 0x34000e20},
{0x0000a534, 0x4d023f01, 0x4d023f01, 0x35000e21, 0x35000e21},
{0x0000a538, 0x53023f4b, 0x53023f4b, 0x43000e62, 0x43000e62},
{0x0000a53c, 0x5a027f09, 0x5a027f09, 0x45000e63, 0x45000e63},
{0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x49000e65, 0x49000e65},
{0x0000a544, 0x6502feca, 0x6502feca, 0x4b000e66, 0x4b000e66},
{0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x4d001645, 0x4d001645},
{0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865},
{0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86},
{0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9},
{0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb},
{0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb},
{0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb},
{0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb},
{0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
{0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
{0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
{0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
{0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
{0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
{0x0000a580, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a584, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a588, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a58c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a590, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a594, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a598, 0x00000000, 0x00000000, 0x01404501, 0x01404501},
{0x0000a59c, 0x00000000, 0x00000000, 0x02808a02, 0x02808a02},
{0x0000a5a0, 0x00000000, 0x00000000, 0x02808a02, 0x02808a02},
{0x0000a5a4, 0x00000000, 0x00000000, 0x02808803, 0x02808803},
{0x0000a5a8, 0x00000000, 0x00000000, 0x04c14b04, 0x04c14b04},
{0x0000a5ac, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305},
{0x0000a5b0, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305},
{0x0000a5b4, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305},
{0x0000a5b8, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305},
{0x0000a5bc, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305},
{0x0000b500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b504, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b508, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b50c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b510, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b514, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b518, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b51c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b520, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b524, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b528, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b52c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b530, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b534, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b538, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b53c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b540, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b544, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b548, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b54c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b550, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b554, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b558, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b55c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b560, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b564, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b568, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b56c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b570, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b574, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b578, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000b57c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x00016044, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db},
{0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260},
};
#define ar9485_modes_lowest_ob_db_tx_gain_1_1 ar9485Modes_low_ob_db_tx_gain_1_1
@ -245,19 +455,19 @@ static const u32 ar9485_1_1[][2] = {
{0x0000a580, 0x00000000},
{0x0000a584, 0x00000000},
{0x0000a588, 0x00000000},
{0x0000a58c, 0x00000000},
{0x0000a590, 0x00000000},
{0x0000a594, 0x00000000},
{0x0000a598, 0x00000000},
{0x0000a59c, 0x00000000},
{0x0000a5a0, 0x00000000},
{0x0000a5a4, 0x00000000},
{0x0000a5a8, 0x00000000},
{0x0000a5ac, 0x00000000},
{0x0000a5b0, 0x00000000},
{0x0000a5b4, 0x00000000},
{0x0000a5b8, 0x00000000},
{0x0000a5bc, 0x00000000},
{0x0000a58c, 0x01804000},
{0x0000a590, 0x02808a02},
{0x0000a594, 0x0340ca02},
{0x0000a598, 0x0340cd03},
{0x0000a59c, 0x0340cd03},
{0x0000a5a0, 0x06415304},
{0x0000a5a4, 0x04c11905},
{0x0000a5a8, 0x06415905},
{0x0000a5ac, 0x06415905},
{0x0000a5b0, 0x06415905},
{0x0000a5b4, 0x06415905},
{0x0000a5b8, 0x06415905},
{0x0000a5bc, 0x06415905},
};
static const u32 ar9485_1_1_radio_core[][2] = {
@ -340,7 +550,7 @@ static const u32 ar9485_1_1_baseband_core[][2] = {
{0x00009880, 0x201fff00},
{0x00009884, 0x00001042},
{0x000098a4, 0x00200400},
{0x000098b0, 0x52440bbe},
{0x000098b0, 0x32840bbe},
{0x000098d0, 0x004b6a8e},
{0x000098d4, 0x00000820},
{0x000098dc, 0x00000000},
@ -362,7 +572,7 @@ static const u32 ar9485_1_1_baseband_core[][2] = {
{0x00009d18, 0x00000000},
{0x00009d1c, 0x00000000},
{0x00009e08, 0x0038233c},
{0x00009e24, 0x9927b515},
{0x00009e24, 0x992bb515},
{0x00009e28, 0x12ef0200},
{0x00009e30, 0x06336f77},
{0x00009e34, 0x6af6532f},
@ -427,7 +637,7 @@ static const u32 ar9485_1_1_baseband_core[][2] = {
{0x0000a408, 0x0e79e5c6},
{0x0000a40c, 0x00820820},
{0x0000a414, 0x1ce739cf},
{0x0000a418, 0x2d0019ce},
{0x0000a418, 0x2d0021ce},
{0x0000a41c, 0x1ce739ce},
{0x0000a420, 0x000001ce},
{0x0000a424, 0x1ce739ce},
@ -443,8 +653,8 @@ static const u32 ar9485_1_1_baseband_core[][2] = {
{0x0000a44c, 0x00000001},
{0x0000a450, 0x00010000},
{0x0000a5c4, 0xbfad9d74},
{0x0000a5c8, 0x0048060a},
{0x0000a5cc, 0x00000637},
{0x0000a5c8, 0x00480605},
{0x0000a5cc, 0x00002e37},
{0x0000a760, 0x03020100},
{0x0000a764, 0x09080504},
{0x0000a768, 0x0d0c0b0a},
@ -464,17 +674,22 @@ static const u32 ar9485_1_1_baseband_core[][2] = {
static const u32 ar9485_common_rx_gain_1_1[][2] = {
/* Addr allmodes */
{0x0000a000, 0x00010000},
{0x0000a004, 0x00030002},
{0x0000a008, 0x00050004},
{0x0000a00c, 0x00810080},
{0x0000a010, 0x01800082},
{0x0000a014, 0x01820181},
{0x0000a018, 0x01840183},
{0x0000a01c, 0x01880185},
{0x0000a020, 0x018a0189},
{0x0000a024, 0x02850284},
{0x0000a028, 0x02890288},
{0x00009e00, 0x03721b20},
{0x00009e04, 0x00082020},
{0x00009e18, 0x0300501e},
{0x00009e2c, 0x00002e21},
{0x00009e44, 0x02182324},
{0x0000a000, 0x00060005},
{0x0000a004, 0x00810080},
{0x0000a008, 0x00830082},
{0x0000a00c, 0x00850084},
{0x0000a010, 0x01820181},
{0x0000a014, 0x01840183},
{0x0000a018, 0x01880185},
{0x0000a01c, 0x018a0189},
{0x0000a020, 0x02850284},
{0x0000a024, 0x02890288},
{0x0000a028, 0x028b028a},
{0x0000a02c, 0x03850384},
{0x0000a030, 0x03890388},
{0x0000a034, 0x038b038a},
@ -496,15 +711,15 @@ static const u32 ar9485_common_rx_gain_1_1[][2] = {
{0x0000a074, 0x00000000},
{0x0000a078, 0x00000000},
{0x0000a07c, 0x00000000},
{0x0000a080, 0x28282828},
{0x0000a084, 0x28282828},
{0x0000a088, 0x28282828},
{0x0000a08c, 0x28282828},
{0x0000a090, 0x28282828},
{0x0000a094, 0x21212128},
{0x0000a098, 0x171c1c1c},
{0x0000a09c, 0x02020212},
{0x0000a0a0, 0x00000202},
{0x0000a080, 0x18181818},
{0x0000a084, 0x18181818},
{0x0000a088, 0x18181818},
{0x0000a08c, 0x18181818},
{0x0000a090, 0x18181818},
{0x0000a094, 0x18181818},
{0x0000a098, 0x17181818},
{0x0000a09c, 0x02020b0b},
{0x0000a0a0, 0x02020202},
{0x0000a0a4, 0x00000000},
{0x0000a0a8, 0x00000000},
{0x0000a0ac, 0x00000000},
@ -512,22 +727,22 @@ static const u32 ar9485_common_rx_gain_1_1[][2] = {
{0x0000a0b4, 0x00000000},
{0x0000a0b8, 0x00000000},
{0x0000a0bc, 0x00000000},
{0x0000a0c0, 0x001f0000},
{0x0000a0c4, 0x111f1100},
{0x0000a0c8, 0x111d111e},
{0x0000a0cc, 0x111b111c},
{0x0000a0d0, 0x22032204},
{0x0000a0d4, 0x22012202},
{0x0000a0d8, 0x221f2200},
{0x0000a0dc, 0x221d221e},
{0x0000a0e0, 0x33013302},
{0x0000a0e4, 0x331f3300},
{0x0000a0e8, 0x4402331e},
{0x0000a0ec, 0x44004401},
{0x0000a0f0, 0x441e441f},
{0x0000a0f4, 0x55015502},
{0x0000a0f8, 0x551f5500},
{0x0000a0fc, 0x6602551e},
{0x0000a0c0, 0x22072208},
{0x0000a0c4, 0x22052206},
{0x0000a0c8, 0x22032204},
{0x0000a0cc, 0x22012202},
{0x0000a0d0, 0x221f2200},
{0x0000a0d4, 0x221d221e},
{0x0000a0d8, 0x33023303},
{0x0000a0dc, 0x33003301},
{0x0000a0e0, 0x331e331f},
{0x0000a0e4, 0x4402331d},
{0x0000a0e8, 0x44004401},
{0x0000a0ec, 0x441e441f},
{0x0000a0f0, 0x55025503},
{0x0000a0f4, 0x55005501},
{0x0000a0f8, 0x551e551f},
{0x0000a0fc, 0x6602551d},
{0x0000a100, 0x66006601},
{0x0000a104, 0x661e661f},
{0x0000a108, 0x7703661d},
@ -636,17 +851,12 @@ static const u32 ar9485_1_1_baseband_postamble[][5] = {
{0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
{0x00009830, 0x0000059c, 0x0000059c, 0x0000059c, 0x0000059c},
{0x00009c00, 0x00000044, 0x00000044, 0x00000044, 0x00000044},
{0x00009e00, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0},
{0x00009e04, 0x00182020, 0x00182020, 0x00182020, 0x00182020},
{0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2},
{0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec80d2e, 0x7ec80d2e},
{0x00009e14, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e},
{0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x00009e14, 0x31395d53, 0x31396053, 0x312e6053, 0x312e5d53},
{0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
{0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
{0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021},
{0x00009e3c, 0xcf946220, 0xcf946220, 0xcf946222, 0xcf946222},
{0x00009e44, 0x02321e27, 0x02321e27, 0x02282324, 0x02282324},
{0x00009e48, 0x5030201a, 0x5030201a, 0x50302010, 0x50302010},
{0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
{0x0000a204, 0x01303fc0, 0x01303fc4, 0x01303fc4, 0x01303fc0},
@ -850,4 +1060,6 @@ static const u32 ar9485_1_1_mac_core[][2] = {
{0x000083d0, 0x000301ff},
};
#define ar9485_1_1_baseband_core_txfir_coeff_japan_2484 ar9462_2p0_baseband_core_txfir_coeff_japan_2484
#endif /* INITVALS_9485_H */

View File

@ -129,10 +129,10 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd,
#define ATH_TXMAXTRY 13
#define TID_TO_WME_AC(_tid) \
((((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE : \
(((_tid) == 1) || ((_tid) == 2)) ? WME_AC_BK : \
(((_tid) == 4) || ((_tid) == 5)) ? WME_AC_VI : \
WME_AC_VO)
((((_tid) == 0) || ((_tid) == 3)) ? IEEE80211_AC_BE : \
(((_tid) == 1) || ((_tid) == 2)) ? IEEE80211_AC_BK : \
(((_tid) == 4) || ((_tid) == 5)) ? IEEE80211_AC_VI : \
IEEE80211_AC_VO)
#define ATH_AGGR_DELIM_SZ 4
#define ATH_AGGR_MINPLEN 256 /* in bytes, minimum packet length */
@ -259,13 +259,10 @@ struct ath_atx_tid {
};
struct ath_node {
#ifdef CONFIG_ATH9K_DEBUGFS
struct list_head list; /* for sc->nodes */
#endif
struct ieee80211_sta *sta; /* station struct we're part of */
struct ieee80211_vif *vif; /* interface with which we're associated */
struct ath_atx_tid tid[WME_NUM_TID];
struct ath_atx_ac ac[WME_NUM_AC];
struct ath_atx_ac ac[IEEE80211_NUM_ACS];
int ps_key;
u16 maxampdu;
@ -299,9 +296,9 @@ struct ath_tx {
struct list_head txbuf;
struct ath_txq txq[ATH9K_NUM_TX_QUEUES];
struct ath_descdma txdma;
struct ath_txq *txq_map[WME_NUM_AC];
u32 txq_max_pending[WME_NUM_AC];
u16 max_aggr_framelen[WME_NUM_AC][4][32];
struct ath_txq *txq_map[IEEE80211_NUM_ACS];
u32 txq_max_pending[IEEE80211_NUM_ACS];
u16 max_aggr_framelen[IEEE80211_NUM_ACS][4][32];
};
struct ath_rx_edma {
@ -461,6 +458,12 @@ void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type);
/* BTCOEX */
/**********/
#define ATH_DUMP_BTCOEX(_s, _val) \
do { \
len += snprintf(buf + len, size - len, \
"%20s : %10d\n", _s, (_val)); \
} while (0)
enum bt_op_flags {
BT_OP_PRIORITY_DETECTED,
BT_OP_SCAN,
@ -482,6 +485,7 @@ struct ath_btcoex {
int rssi_count;
struct ath_gen_timer *no_stomp_timer; /* Timer for no BT stomping */
struct ath_mci_profile mci;
u8 stomp_audio;
};
#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
@ -494,7 +498,7 @@ void ath9k_btcoex_timer_pause(struct ath_softc *sc);
void ath9k_btcoex_handle_interrupt(struct ath_softc *sc, u32 status);
u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, u32 max_4ms_framelen);
void ath9k_btcoex_stop_gen_timer(struct ath_softc *sc);
int ath9k_dump_btcoex(struct ath_softc *sc, u8 *buf, u32 len, u32 size);
int ath9k_dump_btcoex(struct ath_softc *sc, u8 *buf, u32 size);
#else
static inline int ath9k_init_btcoex(struct ath_softc *sc)
{
@ -521,8 +525,7 @@ static inline u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc,
static inline void ath9k_btcoex_stop_gen_timer(struct ath_softc *sc)
{
}
static inline int ath9k_dump_btcoex(struct ath_softc *sc, u8 *buf,
u32 len, u32 size)
static inline int ath9k_dump_btcoex(struct ath_softc *sc, u8 *buf, u32 size)
{
return 0;
}
@ -717,9 +720,6 @@ struct ath_softc {
#ifdef CONFIG_ATH9K_DEBUGFS
struct ath9k_debug debug;
spinlock_t nodes_lock;
struct list_head nodes; /* basically, stations */
unsigned int tx_complete_poll_work_seen;
#endif
struct ath_beacon_config cur_beacon_conf;
struct delayed_work tx_complete_work;

View File

@ -46,7 +46,7 @@ static void ath9k_beaconq_config(struct ath_softc *sc)
qi.tqi_cwmax = 0;
} else {
/* Adhoc mode; important thing is to use 2x cwmin. */
txq = sc->tx.txq_map[WME_AC_BE];
txq = sc->tx.txq_map[IEEE80211_AC_BE];
ath9k_hw_get_txq_props(ah, txq->axq_qnum, &qi_be);
qi.tqi_aifs = qi_be.tqi_aifs;
if (ah->slottime == ATH9K_SLOT_TIME_20)

View File

@ -49,6 +49,7 @@ static const u32 mci_wlan_weights[ATH_BTCOEX_STOMP_MAX]
{ 0x01017d01, 0x3b3b3b01, 0x3b3b3b01, 0x3b3b3b3b }, /* STOMP_LOW */
{ 0x01017d01, 0x01010101, 0x01010101, 0x01010101 }, /* STOMP_NONE */
{ 0x01017d01, 0x013b0101, 0x3b3b0101, 0x3b3b013b }, /* STOMP_LOW_FTP */
{ 0xffffff01, 0xffffffff, 0xffffff01, 0xffffffff }, /* STOMP_AUDIO */
};
void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum)

View File

@ -50,6 +50,7 @@ enum ath_stomp_type {
ATH_BTCOEX_STOMP_LOW,
ATH_BTCOEX_STOMP_NONE,
ATH_BTCOEX_STOMP_LOW_FTP,
ATH_BTCOEX_STOMP_AUDIO,
ATH_BTCOEX_STOMP_MAX
};

View File

@ -28,13 +28,6 @@
#define WME_MAX_BA WME_BA_BMP_SIZE
#define ATH_TID_MAX_BUFS (2 * WME_MAX_BA)
/* These must match mac80211 skb queue mapping numbers */
#define WME_AC_VO 0
#define WME_AC_VI 1
#define WME_AC_BE 2
#define WME_AC_BK 3
#define WME_NUM_AC 4
#define ATH_RSSI_DUMMY_MARKER 0x127
#define ATH_RSSI_LPF_LEN 10
#define RSSI_LPF_THRESHOLD -20

View File

@ -512,62 +512,19 @@ static const struct file_operations fops_interrupt = {
.llseek = default_llseek,
};
#define PR_QNUM(_n) sc->tx.txq_map[_n]->axq_qnum
#define PR(str, elem) \
do { \
len += snprintf(buf + len, size - len, \
"%s%13u%11u%10u%10u\n", str, \
sc->debug.stats.txstats[PR_QNUM(WME_AC_BE)].elem, \
sc->debug.stats.txstats[PR_QNUM(WME_AC_BK)].elem, \
sc->debug.stats.txstats[PR_QNUM(WME_AC_VI)].elem, \
sc->debug.stats.txstats[PR_QNUM(WME_AC_VO)].elem); \
if (len >= size) \
goto done; \
} while(0)
#define PRX(str, elem) \
do { \
len += snprintf(buf + len, size - len, \
"%s%13u%11u%10u%10u\n", str, \
(unsigned int)(sc->tx.txq_map[WME_AC_BE]->elem), \
(unsigned int)(sc->tx.txq_map[WME_AC_BK]->elem), \
(unsigned int)(sc->tx.txq_map[WME_AC_VI]->elem), \
(unsigned int)(sc->tx.txq_map[WME_AC_VO]->elem)); \
if (len >= size) \
goto done; \
} while(0)
#define PRQLE(str, elem) \
do { \
len += snprintf(buf + len, size - len, \
"%s%13i%11i%10i%10i\n", str, \
list_empty(&sc->tx.txq_map[WME_AC_BE]->elem), \
list_empty(&sc->tx.txq_map[WME_AC_BK]->elem), \
list_empty(&sc->tx.txq_map[WME_AC_VI]->elem), \
list_empty(&sc->tx.txq_map[WME_AC_VO]->elem)); \
if (len >= size) \
goto done; \
} while (0)
static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath_softc *sc = file->private_data;
char *buf;
unsigned int len = 0, size = 8000;
int i;
unsigned int len = 0, size = 2048;
ssize_t retval = 0;
char tmp[32];
buf = kzalloc(size, GFP_KERNEL);
if (buf == NULL)
return -ENOMEM;
len += sprintf(buf, "Num-Tx-Queues: %i tx-queues-setup: 0x%x"
" poll-work-seen: %u\n"
"%30s %10s%10s%10s\n\n",
ATH9K_NUM_TX_QUEUES, sc->tx.txqsetup,
sc->tx_complete_poll_work_seen,
len += sprintf(buf, "%30s %10s%10s%10s\n\n",
"BE", "BK", "VI", "VO");
PR("MPDUs Queued: ", queued);
@ -587,62 +544,11 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
PR("DELIM Underrun: ", delim_underrun);
PR("TX-Pkts-All: ", tx_pkts_all);
PR("TX-Bytes-All: ", tx_bytes_all);
PR("hw-put-tx-buf: ", puttxbuf);
PR("hw-tx-start: ", txstart);
PR("hw-tx-proc-desc: ", txprocdesc);
PR("HW-put-tx-buf: ", puttxbuf);
PR("HW-tx-start: ", txstart);
PR("HW-tx-proc-desc: ", txprocdesc);
PR("TX-Failed: ", txfailed);
len += snprintf(buf + len, size - len,
"%s%11p%11p%10p%10p\n", "txq-memory-address:",
sc->tx.txq_map[WME_AC_BE],
sc->tx.txq_map[WME_AC_BK],
sc->tx.txq_map[WME_AC_VI],
sc->tx.txq_map[WME_AC_VO]);
if (len >= size)
goto done;
PRX("axq-qnum: ", axq_qnum);
PRX("axq-depth: ", axq_depth);
PRX("axq-ampdu_depth: ", axq_ampdu_depth);
PRX("axq-stopped ", stopped);
PRX("tx-in-progress ", axq_tx_inprogress);
PRX("pending-frames ", pending_frames);
PRX("txq_headidx: ", txq_headidx);
PRX("txq_tailidx: ", txq_headidx);
PRQLE("axq_q empty: ", axq_q);
PRQLE("axq_acq empty: ", axq_acq);
for (i = 0; i < ATH_TXFIFO_DEPTH; i++) {
snprintf(tmp, sizeof(tmp) - 1, "txq_fifo[%i] empty: ", i);
PRQLE(tmp, txq_fifo[i]);
}
/* Print out more detailed queue-info */
for (i = 0; i <= WME_AC_BK; i++) {
struct ath_txq *txq = &(sc->tx.txq[i]);
struct ath_atx_ac *ac;
struct ath_atx_tid *tid;
if (len >= size)
goto done;
spin_lock_bh(&txq->axq_lock);
if (!list_empty(&txq->axq_acq)) {
ac = list_first_entry(&txq->axq_acq, struct ath_atx_ac,
list);
len += snprintf(buf + len, size - len,
"txq[%i] first-ac: %p sched: %i\n",
i, ac, ac->sched);
if (list_empty(&ac->tid_q) || (len >= size))
goto done_for;
tid = list_first_entry(&ac->tid_q, struct ath_atx_tid,
list);
len += snprintf(buf + len, size - len,
" first-tid: %p sched: %i paused: %i\n",
tid, tid->sched, tid->paused);
}
done_for:
spin_unlock_bh(&txq->axq_lock);
}
done:
if (len > size)
len = size;
@ -652,62 +558,41 @@ done:
return retval;
}
static ssize_t read_file_stations(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
static ssize_t read_file_queues(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath_softc *sc = file->private_data;
struct ath_txq *txq;
char *buf;
unsigned int len = 0, size = 64000;
struct ath_node *an = NULL;
unsigned int len = 0, size = 1024;
ssize_t retval = 0;
int q;
int i;
char *qname[4] = {"VO", "VI", "BE", "BK"};
buf = kzalloc(size, GFP_KERNEL);
if (buf == NULL)
return -ENOMEM;
len += snprintf(buf + len, size - len,
"Stations:\n"
" tid: addr sched paused buf_q-empty an ac baw\n"
" ac: addr sched tid_q-empty txq\n");
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
txq = sc->tx.txq_map[i];
len += snprintf(buf + len, size - len, "(%s): ", qname[i]);
spin_lock(&sc->nodes_lock);
list_for_each_entry(an, &sc->nodes, list) {
unsigned short ma = an->maxampdu;
if (ma == 0)
ma = 65535; /* see ath_lookup_rate */
len += snprintf(buf + len, size - len,
"iface: %pM sta: %pM max-ampdu: %hu mpdu-density: %uus\n",
an->vif->addr, an->sta->addr, ma,
(unsigned int)(an->mpdudensity));
if (len >= size)
goto done;
ath_txq_lock(sc, txq);
for (q = 0; q < WME_NUM_TID; q++) {
struct ath_atx_tid *tid = &(an->tid[q]);
len += snprintf(buf + len, size - len,
" tid: %p %s %s %i %p %p %hu\n",
tid, tid->sched ? "sched" : "idle",
tid->paused ? "paused" : "running",
skb_queue_empty(&tid->buf_q),
tid->an, tid->ac, tid->baw_size);
if (len >= size)
goto done;
}
len += snprintf(buf + len, size - len, "%s: %d ",
"qnum", txq->axq_qnum);
len += snprintf(buf + len, size - len, "%s: %2d ",
"qdepth", txq->axq_depth);
len += snprintf(buf + len, size - len, "%s: %2d ",
"ampdu-depth", txq->axq_ampdu_depth);
len += snprintf(buf + len, size - len, "%s: %3d ",
"pending", txq->pending_frames);
len += snprintf(buf + len, size - len, "%s: %d\n",
"stopped", txq->stopped);
for (q = 0; q < WME_NUM_AC; q++) {
struct ath_atx_ac *ac = &(an->ac[q]);
len += snprintf(buf + len, size - len,
" ac: %p %s %i %p\n",
ac, ac->sched ? "sched" : "idle",
list_empty(&ac->tid_q), ac->txq);
if (len >= size)
goto done;
}
ath_txq_unlock(sc, txq);
}
done:
spin_unlock(&sc->nodes_lock);
if (len > size)
len = size;
@ -837,6 +722,9 @@ static ssize_t read_file_reset(struct file *file, char __user *user_buf,
len += snprintf(buf + len, sizeof(buf) - len,
"%17s: %2d\n", "PLL RX Hang",
sc->debug.stats.reset[RESET_TYPE_PLL_HANG]);
len += snprintf(buf + len, sizeof(buf) - len,
"%17s: %2d\n", "MCI Reset",
sc->debug.stats.reset[RESET_TYPE_MCI]);
if (len > sizeof(buf))
len = sizeof(buf);
@ -919,8 +807,8 @@ static const struct file_operations fops_xmit = {
.llseek = default_llseek,
};
static const struct file_operations fops_stations = {
.read = read_file_stations,
static const struct file_operations fops_queues = {
.read = read_file_queues,
.open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
@ -1599,8 +1487,14 @@ static ssize_t read_file_btcoex(struct file *file, char __user *user_buf,
if (buf == NULL)
return -ENOMEM;
len = ath9k_dump_btcoex(sc, buf, len, size);
if (!sc->sc_ah->common.btcoex_enabled) {
len = snprintf(buf, size, "%s\n",
"BTCOEX is disabled");
goto exit;
}
len = ath9k_dump_btcoex(sc, buf, size);
exit:
retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
kfree(buf);
@ -1638,16 +1532,16 @@ int ath9k_init_debug(struct ath_hw *ah)
&fops_interrupt);
debugfs_create_file("xmit", S_IRUSR, sc->debug.debugfs_phy, sc,
&fops_xmit);
debugfs_create_file("queues", S_IRUSR, sc->debug.debugfs_phy, sc,
&fops_queues);
debugfs_create_u32("qlen_bk", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
&sc->tx.txq_max_pending[WME_AC_BK]);
&sc->tx.txq_max_pending[IEEE80211_AC_BK]);
debugfs_create_u32("qlen_be", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
&sc->tx.txq_max_pending[WME_AC_BE]);
&sc->tx.txq_max_pending[IEEE80211_AC_BE]);
debugfs_create_u32("qlen_vi", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
&sc->tx.txq_max_pending[WME_AC_VI]);
&sc->tx.txq_max_pending[IEEE80211_AC_VI]);
debugfs_create_u32("qlen_vo", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
&sc->tx.txq_max_pending[WME_AC_VO]);
debugfs_create_file("stations", S_IRUSR, sc->debug.debugfs_phy, sc,
&fops_stations);
&sc->tx.txq_max_pending[IEEE80211_AC_VO]);
debugfs_create_file("misc", S_IRUSR, sc->debug.debugfs_phy, sc,
&fops_misc);
debugfs_create_file("reset", S_IRUSR, sc->debug.debugfs_phy, sc,

View File

@ -41,6 +41,7 @@ enum ath_reset_type {
RESET_TYPE_PLL_HANG,
RESET_TYPE_MAC_HANG,
RESET_TYPE_BEACON_STUCK,
RESET_TYPE_MCI,
__RESET_TYPE_MAX
};
@ -178,6 +179,21 @@ struct ath_tx_stats {
u32 txfailed;
};
/*
* Various utility macros to print TX/Queue counters.
*/
#define PR_QNUM(_n) sc->tx.txq_map[_n]->axq_qnum
#define TXSTATS sc->debug.stats.txstats
#define PR(str, elem) \
do { \
len += snprintf(buf + len, size - len, \
"%s%13u%11u%10u%10u\n", str, \
TXSTATS[PR_QNUM(IEEE80211_AC_BE)].elem, \
TXSTATS[PR_QNUM(IEEE80211_AC_BK)].elem, \
TXSTATS[PR_QNUM(IEEE80211_AC_VI)].elem, \
TXSTATS[PR_QNUM(IEEE80211_AC_VO)].elem); \
} while(0)
#define RX_STAT_INC(c) (sc->debug.stats.rxstats.c++)
/**
@ -226,7 +242,7 @@ struct ath_rx_stats {
struct ath_stats {
struct ath_interrupt_stats istats;
struct ath_tx_stats txstats[ATH9K_NUM_TX_QUEUES];
struct ath_tx_stats txstats[IEEE80211_NUM_ACS];
struct ath_rx_stats rxstats;
struct ath_dfs_stats dfs_stats;
u32 reset[__RESET_TYPE_MAX];

View File

@ -42,10 +42,15 @@ struct radar_types {
#define MIN_PPB_THRESH 50
#define PPB_THRESH(PPB) ((PPB * MIN_PPB_THRESH + 50) / 100)
#define PRF2PRI(PRF) ((1000000 + PRF / 2) / PRF)
/* percentage of pulse width tolerance */
#define WIDTH_TOLERANCE 5
#define WIDTH_LOWER(X) ((X*(100-WIDTH_TOLERANCE)+50)/100)
#define WIDTH_UPPER(X) ((X*(100+WIDTH_TOLERANCE)+50)/100)
#define ETSI_PATTERN(ID, WMIN, WMAX, PMIN, PMAX, PRF, PPB) \
{ \
ID, WMIN, WMAX, (PRF2PRI(PMAX) - PRI_TOLERANCE), \
ID, WIDTH_LOWER(WMIN), WIDTH_UPPER(WMAX), \
(PRF2PRI(PMAX) - PRI_TOLERANCE), \
(PRF2PRI(PMIN) * PRF + PRI_TOLERANCE), PRF, PPB * PRF, \
PPB_THRESH(PPB), PRI_TOLERANCE, \
}
@ -274,7 +279,7 @@ static bool dpd_set_domain(struct dfs_pattern_detector *dpd,
static struct dfs_pattern_detector default_dpd = {
.exit = dpd_exit,
.set_domain = dpd_set_domain,
.set_dfs_domain = dpd_set_domain,
.add_pulse = dpd_add_pulse,
.region = NL80211_DFS_UNSET,
};
@ -291,10 +296,11 @@ dfs_pattern_detector_init(enum nl80211_dfs_regions region)
*dpd = default_dpd;
INIT_LIST_HEAD(&dpd->channel_detectors);
if (dpd->set_domain(dpd, region))
if (dpd->set_dfs_domain(dpd, region))
return dpd;
pr_err("Could not set DFS domain to %d. ", region);
kfree(dpd);
return NULL;
}
EXPORT_SYMBOL(dfs_pattern_detector_init);

View File

@ -62,7 +62,7 @@ struct radar_detector_specs {
/**
* struct dfs_pattern_detector - DFS pattern detector
* @exit(): destructor
* @set_domain(): set DFS domain, resets detector lines upon domain changes
* @set_dfs_domain(): set DFS domain, resets detector lines upon domain changes
* @add_pulse(): add radar pulse to detector, returns true on detection
* @region: active DFS region, NL80211_DFS_UNSET until set
* @num_radar_types: number of different radar types
@ -72,7 +72,7 @@ struct radar_detector_specs {
*/
struct dfs_pattern_detector {
void (*exit)(struct dfs_pattern_detector *dpd);
bool (*set_domain)(struct dfs_pattern_detector *dpd,
bool (*set_dfs_domain)(struct dfs_pattern_detector *dpd,
enum nl80211_dfs_regions region);
bool (*add_pulse)(struct dfs_pattern_detector *dpd,
struct pulse_event *pe);

View File

@ -247,6 +247,9 @@ static void ath_btcoex_period_timer(unsigned long data)
stomp_type = ATH_BTCOEX_STOMP_ALL;
timer_period = btcoex->btscan_no_stomp;
}
} else if (btcoex->stomp_audio >= 5) {
stomp_type = ATH_BTCOEX_STOMP_AUDIO;
btcoex->stomp_audio = 0;
}
ath9k_hw_btcoex_bt_stomp(ah, stomp_type);
@ -295,7 +298,7 @@ static void ath_btcoex_no_stomp_timer(void *arg)
(!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI) &&
test_bit(BT_OP_SCAN, &btcoex->op_flags)))
ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_NONE);
else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL)
else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL)
ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_LOW);
ath9k_hw_btcoex_enable(ah);
@ -471,7 +474,7 @@ int ath9k_init_btcoex(struct ath_softc *sc)
r = ath_init_btcoex_timer(sc);
if (r)
return -1;
txq = sc->tx.txq_map[WME_AC_BE];
txq = sc->tx.txq_map[IEEE80211_AC_BE];
ath9k_hw_init_btcoex_hw(sc->sc_ah, txq->axq_qnum);
sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
if (ath9k_hw_mci_is_enabled(ah)) {
@ -494,35 +497,31 @@ int ath9k_init_btcoex(struct ath_softc *sc)
return 0;
}
int ath9k_dump_btcoex(struct ath_softc *sc, u8 *buf, u32 len, u32 size)
static int ath9k_dump_mci_btcoex(struct ath_softc *sc, u8 *buf, u32 size)
{
#define ATH_DUMP_BTCOEX(_s, _val) \
do { \
len += snprintf(buf + len, size - len, \
"%20s : %10d\n", _s, (_val)); \
} while (0)
struct ath_btcoex *btcoex = &sc->btcoex;
struct ath_mci_profile *mci = &btcoex->mci;
struct ath_hw *ah = sc->sc_ah;
struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
u32 len = 0;
int i;
ATH_DUMP_BTCOEX("Total BT profiles", NUM_PROF(mci));
ATH_DUMP_BTCOEX("Number of MGMT", mci->num_mgmt);
ATH_DUMP_BTCOEX("Number of SCO", mci->num_sco);
ATH_DUMP_BTCOEX("Number of A2DP", mci->num_a2dp);
ATH_DUMP_BTCOEX("Number of HID", mci->num_hid);
ATH_DUMP_BTCOEX("Number of PAN", mci->num_pan);
ATH_DUMP_BTCOEX("Number of ACL", mci->num_other_acl);
ATH_DUMP_BTCOEX("Number of BDR", mci->num_bdr);
ATH_DUMP_BTCOEX("MGMT", mci->num_mgmt);
ATH_DUMP_BTCOEX("SCO", mci->num_sco);
ATH_DUMP_BTCOEX("A2DP", mci->num_a2dp);
ATH_DUMP_BTCOEX("HID", mci->num_hid);
ATH_DUMP_BTCOEX("PAN", mci->num_pan);
ATH_DUMP_BTCOEX("ACL", mci->num_other_acl);
ATH_DUMP_BTCOEX("BDR", mci->num_bdr);
ATH_DUMP_BTCOEX("Aggr. Limit", mci->aggr_limit);
ATH_DUMP_BTCOEX("Stomp Type", btcoex->bt_stomp_type);
ATH_DUMP_BTCOEX("BTCoex Period (msec)", btcoex->btcoex_period);
ATH_DUMP_BTCOEX("Duty Cycle", btcoex->duty_cycle);
ATH_DUMP_BTCOEX("BT Wait time", btcoex->bt_wait_time);
ATH_DUMP_BTCOEX("Concurrent Tx", btcoex_hw->mci.concur_tx);
ATH_DUMP_BTCOEX("Concur RSSI count", btcoex->rssi_count);
ATH_DUMP_BTCOEX("Concurrent RSSI cnt", btcoex->rssi_count);
len += snprintf(buf + len, size - len, "BT Weights: ");
for (i = 0; i < AR9300_NUM_BT_WEIGHTS; i++)
len += snprintf(buf + len, size - len, "%08x ",
@ -537,9 +536,32 @@ int ath9k_dump_btcoex(struct ath_softc *sc, u8 *buf, u32 len, u32 size)
for (i = 0; i < ATH_BTCOEX_STOMP_MAX; i++)
len += snprintf(buf + len, size - len, "%08x ",
btcoex_hw->tx_prio[i]);
len += snprintf(buf + len, size - len, "\n");
#undef ATH_DUMP_BTCOEX
return len;
}
static int ath9k_dump_legacy_btcoex(struct ath_softc *sc, u8 *buf, u32 size)
{
struct ath_btcoex *btcoex = &sc->btcoex;
u32 len = 0;
ATH_DUMP_BTCOEX("Stomp Type", btcoex->bt_stomp_type);
ATH_DUMP_BTCOEX("BTCoex Period (msec)", btcoex->btcoex_period);
ATH_DUMP_BTCOEX("Duty Cycle", btcoex->duty_cycle);
ATH_DUMP_BTCOEX("BT Wait time", btcoex->bt_wait_time);
return len;
}
int ath9k_dump_btcoex(struct ath_softc *sc, u8 *buf, u32 size)
{
if (ath9k_hw_mci_is_enabled(sc->sc_ah))
return ath9k_dump_mci_btcoex(sc, buf, size);
else
return ath9k_dump_legacy_btcoex(sc, buf, size);
}
#endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */

View File

@ -331,7 +331,7 @@ struct ath_tx_stats {
u32 skb_success;
u32 skb_failed;
u32 cab_queued;
u32 queue_stats[WME_NUM_AC];
u32 queue_stats[IEEE80211_NUM_ACS];
};
struct ath_rx_stats {
@ -493,7 +493,7 @@ struct ath9k_htc_priv {
int beaconq;
int cabq;
int hwq_map[WME_NUM_AC];
int hwq_map[IEEE80211_NUM_ACS];
#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
struct ath_btcoex btcoex;

View File

@ -33,7 +33,7 @@ void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv)
qi.tqi_cwmin = 0;
qi.tqi_cwmax = 0;
} else if (priv->ah->opmode == NL80211_IFTYPE_ADHOC) {
int qnum = priv->hwq_map[WME_AC_BE];
int qnum = priv->hwq_map[IEEE80211_AC_BE];
ath9k_hw_get_txq_props(ah, qnum, &qi_be);
@ -587,9 +587,9 @@ static bool ath9k_htc_check_beacon_config(struct ath9k_htc_priv *priv,
(priv->num_sta_vif > 1) &&
(vif->type == NL80211_IFTYPE_STATION)) {
beacon_configured = false;
ieee80211_iterate_active_interfaces_atomic(priv->hw,
ath9k_htc_beacon_iter,
&beacon_configured);
ieee80211_iterate_active_interfaces_atomic(
priv->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
ath9k_htc_beacon_iter, &beacon_configured);
if (beacon_configured) {
ath_dbg(common, CONFIG,

View File

@ -218,16 +218,16 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
len += snprintf(buf + len, sizeof(buf) - len,
"%20s : %10u\n", "BE queued",
priv->debug.tx_stats.queue_stats[WME_AC_BE]);
priv->debug.tx_stats.queue_stats[IEEE80211_AC_BE]);
len += snprintf(buf + len, sizeof(buf) - len,
"%20s : %10u\n", "BK queued",
priv->debug.tx_stats.queue_stats[WME_AC_BK]);
priv->debug.tx_stats.queue_stats[IEEE80211_AC_BK]);
len += snprintf(buf + len, sizeof(buf) - len,
"%20s : %10u\n", "VI queued",
priv->debug.tx_stats.queue_stats[WME_AC_VI]);
priv->debug.tx_stats.queue_stats[IEEE80211_AC_VI]);
len += snprintf(buf + len, sizeof(buf) - len,
"%20s : %10u\n", "VO queued",
priv->debug.tx_stats.queue_stats[WME_AC_VO]);
priv->debug.tx_stats.queue_stats[IEEE80211_AC_VO]);
if (len > sizeof(buf))
len = sizeof(buf);

View File

@ -207,7 +207,7 @@ void ath9k_htc_init_btcoex(struct ath9k_htc_priv *priv, char *product)
priv->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
ath9k_hw_btcoex_init_3wire(priv->ah);
ath_htc_init_btcoex_work(priv);
qnum = priv->hwq_map[WME_AC_BE];
qnum = priv->hwq_map[IEEE80211_AC_BE];
ath9k_hw_init_btcoex_hw(priv->ah, qnum);
break;
default:

View File

@ -549,20 +549,20 @@ static int ath9k_init_queues(struct ath9k_htc_priv *priv)
goto err;
}
if (!ath9k_htc_txq_setup(priv, WME_AC_BE)) {
if (!ath9k_htc_txq_setup(priv, IEEE80211_AC_BE)) {
ath_err(common, "Unable to setup xmit queue for BE traffic\n");
goto err;
}
if (!ath9k_htc_txq_setup(priv, WME_AC_BK)) {
if (!ath9k_htc_txq_setup(priv, IEEE80211_AC_BK)) {
ath_err(common, "Unable to setup xmit queue for BK traffic\n");
goto err;
}
if (!ath9k_htc_txq_setup(priv, WME_AC_VI)) {
if (!ath9k_htc_txq_setup(priv, IEEE80211_AC_VI)) {
ath_err(common, "Unable to setup xmit queue for VI traffic\n");
goto err;
}
if (!ath9k_htc_txq_setup(priv, WME_AC_VO)) {
if (!ath9k_htc_txq_setup(priv, IEEE80211_AC_VO)) {
ath_err(common, "Unable to setup xmit queue for VO traffic\n");
goto err;
}

View File

@ -127,8 +127,9 @@ static void ath9k_htc_vif_reconfig(struct ath9k_htc_priv *priv)
priv->rearm_ani = false;
priv->reconfig_beacon = false;
ieee80211_iterate_active_interfaces_atomic(priv->hw,
ath9k_htc_vif_iter, priv);
ieee80211_iterate_active_interfaces_atomic(
priv->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
ath9k_htc_vif_iter, priv);
if (priv->rearm_ani)
ath9k_htc_start_ani(priv);
@ -165,8 +166,9 @@ static void ath9k_htc_set_bssid_mask(struct ath9k_htc_priv *priv,
ath9k_htc_bssid_iter(&iter_data, vif->addr, vif);
/* Get list of all active MAC addresses */
ieee80211_iterate_active_interfaces_atomic(priv->hw, ath9k_htc_bssid_iter,
&iter_data);
ieee80211_iterate_active_interfaces_atomic(
priv->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
ath9k_htc_bssid_iter, &iter_data);
memcpy(common->bssidmask, iter_data.mask, ETH_ALEN);
ath_hw_setbssidmask(common);
@ -1144,8 +1146,9 @@ static void ath9k_htc_remove_interface(struct ieee80211_hw *hw,
*/
if ((vif->type == NL80211_IFTYPE_AP) && (priv->num_ap_vif == 0)) {
priv->rearm_ani = false;
ieee80211_iterate_active_interfaces_atomic(priv->hw,
ath9k_htc_vif_iter, priv);
ieee80211_iterate_active_interfaces_atomic(
priv->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
ath9k_htc_vif_iter, priv);
if (!priv->rearm_ani)
ath9k_htc_stop_ani(priv);
}
@ -1346,7 +1349,7 @@ static int ath9k_htc_conf_tx(struct ieee80211_hw *hw,
struct ath9k_tx_queue_info qi;
int ret = 0, qnum;
if (queue >= WME_NUM_AC)
if (queue >= IEEE80211_NUM_ACS)
return 0;
mutex_lock(&priv->mutex);
@ -1373,7 +1376,7 @@ static int ath9k_htc_conf_tx(struct ieee80211_hw *hw,
}
if ((priv->ah->opmode == NL80211_IFTYPE_ADHOC) &&
(qnum == priv->hwq_map[WME_AC_BE]))
(qnum == priv->hwq_map[IEEE80211_AC_BE]))
ath9k_htc_beaconq_config(priv);
out:
ath9k_htc_ps_restore(priv);
@ -1466,8 +1469,9 @@ static void ath9k_htc_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
static void ath9k_htc_choose_set_bssid(struct ath9k_htc_priv *priv)
{
if (priv->num_sta_assoc_vif == 1) {
ieee80211_iterate_active_interfaces_atomic(priv->hw,
ath9k_htc_bss_iter, priv);
ieee80211_iterate_active_interfaces_atomic(
priv->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
ath9k_htc_bss_iter, priv);
ath9k_htc_set_bssid(priv);
}
}

View File

@ -21,10 +21,10 @@
/******/
static const int subtype_txq_to_hwq[] = {
[WME_AC_BE] = ATH_TXQ_AC_BE,
[WME_AC_BK] = ATH_TXQ_AC_BK,
[WME_AC_VI] = ATH_TXQ_AC_VI,
[WME_AC_VO] = ATH_TXQ_AC_VO,
[IEEE80211_AC_BE] = ATH_TXQ_AC_BE,
[IEEE80211_AC_BK] = ATH_TXQ_AC_BK,
[IEEE80211_AC_VI] = ATH_TXQ_AC_VI,
[IEEE80211_AC_VO] = ATH_TXQ_AC_VO,
};
#define ATH9K_HTC_INIT_TXQ(subtype) do { \
@ -41,15 +41,15 @@ int get_hw_qnum(u16 queue, int *hwq_map)
{
switch (queue) {
case 0:
return hwq_map[WME_AC_VO];
return hwq_map[IEEE80211_AC_VO];
case 1:
return hwq_map[WME_AC_VI];
return hwq_map[IEEE80211_AC_VI];
case 2:
return hwq_map[WME_AC_BE];
return hwq_map[IEEE80211_AC_BE];
case 3:
return hwq_map[WME_AC_BK];
return hwq_map[IEEE80211_AC_BK];
default:
return hwq_map[WME_AC_BE];
return hwq_map[IEEE80211_AC_BE];
}
}
@ -106,20 +106,20 @@ static inline enum htc_endpoint_id get_htc_epid(struct ath9k_htc_priv *priv,
switch (qnum) {
case 0:
TX_QSTAT_INC(WME_AC_VO);
TX_QSTAT_INC(IEEE80211_AC_VO);
epid = priv->data_vo_ep;
break;
case 1:
TX_QSTAT_INC(WME_AC_VI);
TX_QSTAT_INC(IEEE80211_AC_VI);
epid = priv->data_vi_ep;
break;
case 2:
TX_QSTAT_INC(WME_AC_BE);
TX_QSTAT_INC(IEEE80211_AC_BE);
epid = priv->data_be_ep;
break;
case 3:
default:
TX_QSTAT_INC(WME_AC_BK);
TX_QSTAT_INC(IEEE80211_AC_BK);
epid = priv->data_bk_ep;
break;
}
@ -1082,7 +1082,7 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv,
rx_status->freq = hw->conf.channel->center_freq;
rx_status->signal = rxbuf->rxstatus.rs_rssi + ATH_DEFAULT_NOISE_FLOOR;
rx_status->antenna = rxbuf->rxstatus.rs_antenna;
rx_status->flag |= RX_FLAG_MACTIME_MPDU;
rx_status->flag |= RX_FLAG_MACTIME_START;
return true;

View File

@ -2561,11 +2561,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
pCap->hw_caps |= ATH9K_HW_CAP_ANT_DIV_COMB;
}
if (AR_SREV_9485_10(ah)) {
pCap->pcie_lcr_extsync_en = true;
pCap->pcie_lcr_offset = 0x80;
}
if (ath9k_hw_dfs_tested(ah))
pCap->hw_caps |= ATH9K_HW_CAP_DFS;

View File

@ -273,8 +273,6 @@ struct ath9k_hw_capabilities {
u8 rx_status_len;
u8 tx_desc_len;
u8 txs_len;
u16 pcie_lcr_offset;
bool pcie_lcr_extsync_en;
};
struct ath9k_ops_config {
@ -877,7 +875,6 @@ struct ath_hw {
struct ar5416IniArray iniModesTxGain;
struct ar5416IniArray iniCckfirNormal;
struct ar5416IniArray iniCckfirJapan2484;
struct ar5416IniArray ini_japan2484;
struct ar5416IniArray iniModes_9271_ANI_reg;
struct ar5416IniArray ini_radio_post_sys2ant;
@ -930,7 +927,6 @@ struct ath_bus_ops {
void (*read_cachesize)(struct ath_common *common, int *csz);
bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data);
void (*bt_coex_prep)(struct ath_common *common);
void (*extn_synch_en)(struct ath_common *common);
void (*aspm_init)(struct ath_common *common);
};

View File

@ -435,7 +435,7 @@ static int ath9k_init_queues(struct ath_softc *sc)
sc->config.cabqReadytime = ATH_CABQ_READY_TIME;
ath_cabq_update(sc);
for (i = 0; i < WME_NUM_AC; i++) {
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
sc->tx.txq_map[i] = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, i);
sc->tx.txq_map[i]->mac80211_qnum = i;
sc->tx.txq_max_pending[i] = ATH_MAX_QDEPTH;
@ -563,10 +563,6 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
spin_lock_init(&sc->sc_serial_rw);
spin_lock_init(&sc->sc_pm_lock);
mutex_init(&sc->mutex);
#ifdef CONFIG_ATH9K_DEBUGFS
spin_lock_init(&sc->nodes_lock);
INIT_LIST_HEAD(&sc->nodes);
#endif
#ifdef CONFIG_ATH9K_MAC_DEBUG
spin_lock_init(&sc->debug.samp_lock);
#endif

View File

@ -27,9 +27,6 @@ void ath_tx_complete_poll_work(struct work_struct *work)
struct ath_txq *txq;
int i;
bool needreset = false;
#ifdef CONFIG_ATH9K_DEBUGFS
sc->tx_complete_poll_work_seen++;
#endif
for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
if (ATH_TXQ_SETUP(sc, i)) {
@ -211,7 +208,7 @@ static bool ath_paprd_send_frame(struct ath_softc *sc, struct sk_buff *skb, int
int time_left;
memset(&txctl, 0, sizeof(txctl));
txctl.txq = sc->tx.txq_map[WME_AC_BE];
txctl.txq = sc->tx.txq_map[IEEE80211_AC_BE];
memset(tx_info, 0, sizeof(*tx_info));
tx_info->band = hw->conf.channel->band;

View File

@ -331,11 +331,6 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta,
u8 density;
an = (struct ath_node *)sta->drv_priv;
#ifdef CONFIG_ATH9K_DEBUGFS
spin_lock(&sc->nodes_lock);
list_add(&an->list, &sc->nodes);
spin_unlock(&sc->nodes_lock);
#endif
an->sta = sta;
an->vif = vif;
@ -352,13 +347,6 @@ static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta)
{
struct ath_node *an = (struct ath_node *)sta->drv_priv;
#ifdef CONFIG_ATH9K_DEBUGFS
spin_lock(&sc->nodes_lock);
list_del(&an->list);
spin_unlock(&sc->nodes_lock);
an->sta = NULL;
#endif
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT)
ath_tx_node_cleanup(sc, an);
}
@ -494,17 +482,6 @@ irqreturn_t ath_isr(int irq, void *dev)
if (status & SCHED_INTR)
sched = true;
#ifdef CONFIG_PM_SLEEP
if (status & ATH9K_INT_BMISS) {
if (atomic_read(&sc->wow_sleep_proc_intr) == 0) {
ath_dbg(common, ANY, "during WoW we got a BMISS\n");
atomic_inc(&sc->wow_got_bmiss_intr);
atomic_dec(&sc->wow_sleep_proc_intr);
}
ath_dbg(common, INTERRUPT, "beacon miss interrupt\n");
}
#endif
/*
* If a FATAL or RXORN interrupt is received, we have to reset the
* chip immediately.
@ -523,7 +500,15 @@ irqreturn_t ath_isr(int irq, void *dev)
goto chip_reset;
}
#ifdef CONFIG_PM_SLEEP
if (status & ATH9K_INT_BMISS) {
if (atomic_read(&sc->wow_sleep_proc_intr) == 0) {
ath_dbg(common, ANY, "during WoW we got a BMISS\n");
atomic_inc(&sc->wow_got_bmiss_intr);
atomic_dec(&sc->wow_sleep_proc_intr);
}
}
#endif
if (status & ATH9K_INT_SWBA)
tasklet_schedule(&sc->bcon_tasklet);
@ -686,9 +671,6 @@ static int ath9k_start(struct ieee80211_hw *hw)
spin_unlock_bh(&sc->sc_pcu_lock);
if (ah->caps.pcie_lcr_extsync_en && common->bus_ops->extn_synch_en)
common->bus_ops->extn_synch_en(common);
mutex_unlock(&sc->mutex);
ath9k_ps_restore(sc);
@ -924,8 +906,9 @@ void ath9k_calculate_iter_data(struct ieee80211_hw *hw,
ath9k_vif_iter(iter_data, vif->addr, vif);
/* Get list of all active MAC addresses */
ieee80211_iterate_active_interfaces_atomic(sc->hw, ath9k_vif_iter,
iter_data);
ieee80211_iterate_active_interfaces_atomic(
sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
ath9k_vif_iter, iter_data);
}
/* Called with sc->mutex held. */
@ -975,8 +958,9 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw,
if (ah->opmode == NL80211_IFTYPE_STATION &&
old_opmode == NL80211_IFTYPE_AP &&
test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) {
ieee80211_iterate_active_interfaces_atomic(sc->hw,
ath9k_sta_vif_iter, sc);
ieee80211_iterate_active_interfaces_atomic(
sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
ath9k_sta_vif_iter, sc);
}
}
@ -1329,7 +1313,7 @@ static int ath9k_conf_tx(struct ieee80211_hw *hw,
struct ath9k_tx_queue_info qi;
int ret = 0;
if (queue >= WME_NUM_AC)
if (queue >= IEEE80211_NUM_ACS)
return 0;
txq = sc->tx.txq_map[queue];
@ -1505,8 +1489,9 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
clear_bit(SC_OP_BEACONS, &sc->sc_flags);
}
ieee80211_iterate_active_interfaces_atomic(sc->hw,
ath9k_bss_assoc_iter, sc);
ieee80211_iterate_active_interfaces_atomic(
sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
ath9k_bss_assoc_iter, sc);
if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags) &&
ah->opmode == NL80211_IFTYPE_STATION) {
@ -1956,13 +1941,12 @@ static int ath9k_get_et_sset_count(struct ieee80211_hw *hw,
return 0;
}
#define PR_QNUM(_n) (sc->tx.txq_map[_n]->axq_qnum)
#define AWDATA(elem) \
do { \
data[i++] = sc->debug.stats.txstats[PR_QNUM(WME_AC_BE)].elem; \
data[i++] = sc->debug.stats.txstats[PR_QNUM(WME_AC_BK)].elem; \
data[i++] = sc->debug.stats.txstats[PR_QNUM(WME_AC_VI)].elem; \
data[i++] = sc->debug.stats.txstats[PR_QNUM(WME_AC_VO)].elem; \
data[i++] = sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BE)].elem; \
data[i++] = sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BK)].elem; \
data[i++] = sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VI)].elem; \
data[i++] = sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VO)].elem; \
} while (0)
#define AWDATA_RX(elem) \
@ -1977,14 +1961,14 @@ static void ath9k_get_et_stats(struct ieee80211_hw *hw,
struct ath_softc *sc = hw->priv;
int i = 0;
data[i++] = (sc->debug.stats.txstats[PR_QNUM(WME_AC_BE)].tx_pkts_all +
sc->debug.stats.txstats[PR_QNUM(WME_AC_BK)].tx_pkts_all +
sc->debug.stats.txstats[PR_QNUM(WME_AC_VI)].tx_pkts_all +
sc->debug.stats.txstats[PR_QNUM(WME_AC_VO)].tx_pkts_all);
data[i++] = (sc->debug.stats.txstats[PR_QNUM(WME_AC_BE)].tx_bytes_all +
sc->debug.stats.txstats[PR_QNUM(WME_AC_BK)].tx_bytes_all +
sc->debug.stats.txstats[PR_QNUM(WME_AC_VI)].tx_bytes_all +
sc->debug.stats.txstats[PR_QNUM(WME_AC_VO)].tx_bytes_all);
data[i++] = (sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BE)].tx_pkts_all +
sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BK)].tx_pkts_all +
sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VI)].tx_pkts_all +
sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VO)].tx_pkts_all);
data[i++] = (sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BE)].tx_bytes_all +
sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BK)].tx_bytes_all +
sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VI)].tx_bytes_all +
sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VO)].tx_bytes_all);
AWDATA_RX(rx_pkts_all);
AWDATA_RX(rx_bytes_all);

View File

@ -207,23 +207,6 @@ skip_tuning:
ath9k_btcoex_timer_resume(sc);
}
static void ath_mci_wait_btcal_done(struct ath_softc *sc)
{
struct ath_hw *ah = sc->sc_ah;
/* Stop tx & rx */
ieee80211_stop_queues(sc->hw);
ath_stoprecv(sc);
ath_drain_all_txq(sc, false);
/* Wait for cal done */
ar9003_mci_start_reset(ah, ah->curchan);
/* Resume tx & rx */
ath_startrecv(sc);
ieee80211_wake_queues(sc->hw);
}
static void ath_mci_cal_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload)
{
struct ath_hw *ah = sc->sc_ah;
@ -235,7 +218,7 @@ static void ath_mci_cal_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload)
case MCI_GPM_BT_CAL_REQ:
if (mci_hw->bt_state == MCI_BT_AWAKE) {
mci_hw->bt_state = MCI_BT_CAL_START;
ath_mci_wait_btcal_done(sc);
ath9k_queue_reset(sc, RESET_TYPE_MCI);
}
ath_dbg(common, MCI, "MCI State : %d\n", mci_hw->bt_state);
break;
@ -578,6 +561,8 @@ void ath_mci_intr(struct ath_softc *sc)
mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_GPM;
while (more_data == MCI_GPM_MORE) {
if (test_bit(SC_OP_HW_RESET, &sc->sc_flags))
return;
pgpm = mci->gpm_buf.bf_addr;
offset = ar9003_mci_get_next_gpm_offset(ah, false,
@ -744,12 +729,30 @@ void ath9k_mci_set_txpower(struct ath_softc *sc, bool setchannel,
ath9k_hw_set_txpowerlimit(ah, sc->config.txpowlimit, false);
}
static void ath9k_mci_stomp_audio(struct ath_softc *sc)
{
struct ath_hw *ah = sc->sc_ah;
struct ath_btcoex *btcoex = &sc->btcoex;
struct ath_mci_profile *mci = &btcoex->mci;
if (!mci->num_sco && !mci->num_a2dp)
return;
if (ah->stats.avgbrssi > 25) {
btcoex->stomp_audio = 0;
return;
}
btcoex->stomp_audio++;
}
void ath9k_mci_update_rssi(struct ath_softc *sc)
{
struct ath_hw *ah = sc->sc_ah;
struct ath_btcoex *btcoex = &sc->btcoex;
struct ath9k_hw_mci *mci_hw = &sc->sc_ah->btcoex_hw.mci;
ath9k_mci_stomp_audio(sc);
if (!(mci_hw->config & ATH_MCI_CONFIG_CONCUR_TX))
return;

View File

@ -96,17 +96,6 @@ static bool ath_pci_eeprom_read(struct ath_common *common, u32 off, u16 *data)
return true;
}
static void ath_pci_extn_synch_enable(struct ath_common *common)
{
struct ath_softc *sc = (struct ath_softc *) common->priv;
struct pci_dev *pdev = to_pci_dev(sc->dev);
u8 lnkctl;
pci_read_config_byte(pdev, sc->sc_ah->caps.pcie_lcr_offset, &lnkctl);
lnkctl |= PCI_EXP_LNKCTL_ES;
pci_write_config_byte(pdev, sc->sc_ah->caps.pcie_lcr_offset, lnkctl);
}
/* Need to be called after we discover btcoex capabilities */
static void ath_pci_aspm_init(struct ath_common *common)
{
@ -153,7 +142,6 @@ static const struct ath_bus_ops ath_pci_bus_ops = {
.ath_bus_type = ATH_PCI,
.read_cachesize = ath_pci_read_cachesize,
.eeprom_read = ath_pci_eeprom_read,
.extn_synch_en = ath_pci_extn_synch_enable,
.aspm_init = ath_pci_aspm_init,
};

View File

@ -982,16 +982,6 @@ static void ath_rc_update_per(struct ath_softc *sc,
}
}
static void ath_debug_stat_retries(struct ath_rate_priv *rc, int rix,
int xretries, int retries, u8 per)
{
struct ath_rc_stats *stats = &rc->rcstats[rix];
stats->xretries += xretries;
stats->retries += retries;
stats->per = per;
}
static void ath_rc_update_ht(struct ath_softc *sc,
struct ath_rate_priv *ath_rc_priv,
struct ieee80211_tx_info *tx_info,
@ -1065,14 +1055,6 @@ static void ath_rc_update_ht(struct ath_softc *sc,
}
static void ath_debug_stat_rc(struct ath_rate_priv *rc, int final_rate)
{
struct ath_rc_stats *stats;
stats = &rc->rcstats[final_rate];
stats->success++;
}
static void ath_rc_tx_status(struct ath_softc *sc,
struct ath_rate_priv *ath_rc_priv,
struct sk_buff *skb)
@ -1350,7 +1332,25 @@ static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband,
}
}
#ifdef CONFIG_ATH9K_DEBUGFS
#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS)
void ath_debug_stat_rc(struct ath_rate_priv *rc, int final_rate)
{
struct ath_rc_stats *stats;
stats = &rc->rcstats[final_rate];
stats->success++;
}
void ath_debug_stat_retries(struct ath_rate_priv *rc, int rix,
int xretries, int retries, u8 per)
{
struct ath_rc_stats *stats = &rc->rcstats[rix];
stats->xretries += xretries;
stats->retries += retries;
stats->per = per;
}
static ssize_t read_file_rcstat(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
@ -1428,10 +1428,17 @@ static void ath_rate_add_sta_debugfs(void *priv, void *priv_sta,
struct dentry *dir)
{
struct ath_rate_priv *rc = priv_sta;
debugfs_create_file("rc_stats", S_IRUGO, dir, rc, &fops_rcstat);
rc->debugfs_rcstats = debugfs_create_file("rc_stats", S_IRUGO,
dir, rc, &fops_rcstat);
}
#endif /* CONFIG_ATH9K_DEBUGFS */
static void ath_rate_remove_sta_debugfs(void *priv, void *priv_sta)
{
struct ath_rate_priv *rc = priv_sta;
debugfs_remove(rc->debugfs_rcstats);
}
#endif /* CONFIG_MAC80211_DEBUGFS && CONFIG_ATH9K_DEBUGFS */
static void *ath_rate_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
{
@ -1476,8 +1483,10 @@ static struct rate_control_ops ath_rate_ops = {
.free = ath_rate_free,
.alloc_sta = ath_rate_alloc_sta,
.free_sta = ath_rate_free_sta,
#ifdef CONFIG_ATH9K_DEBUGFS
#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS)
.add_sta_debugfs = ath_rate_add_sta_debugfs,
.remove_sta_debugfs = ath_rate_remove_sta_debugfs,
#endif
};

View File

@ -211,10 +211,26 @@ struct ath_rate_priv {
struct ath_rateset neg_ht_rates;
const struct ath_rate_table *rate_table;
#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS)
struct dentry *debugfs_rcstats;
struct ath_rc_stats rcstats[RATE_TABLE_SIZE];
#endif
};
#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS)
void ath_debug_stat_rc(struct ath_rate_priv *rc, int final_rate);
void ath_debug_stat_retries(struct ath_rate_priv *rc, int rix,
int xretries, int retries, u8 per);
#else
static inline void ath_debug_stat_rc(struct ath_rate_priv *rc, int final_rate)
{
}
static inline void ath_debug_stat_retries(struct ath_rate_priv *rc, int rix,
int xretries, int retries, u8 per)
{
}
#endif
#ifdef CONFIG_ATH9K_RATE_CONTROL
int ath_rate_control_register(void);
void ath_rate_control_unregister(void);

View File

@ -976,7 +976,7 @@ static int ath9k_rx_skb_preprocess(struct ath_common *common,
rx_status->freq = hw->conf.channel->center_freq;
rx_status->signal = ah->noise + rx_stats->rs_rssi;
rx_status->antenna = rx_stats->rs_antenna;
rx_status->flag |= RX_FLAG_MACTIME_MPDU;
rx_status->flag |= RX_FLAG_MACTIME_START;
if (rx_stats->rs_moreaggr)
rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL;

View File

@ -1354,10 +1354,10 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
struct ath_hw *ah = sc->sc_ah;
struct ath9k_tx_queue_info qi;
static const int subtype_txq_to_hwq[] = {
[WME_AC_BE] = ATH_TXQ_AC_BE,
[WME_AC_BK] = ATH_TXQ_AC_BK,
[WME_AC_VI] = ATH_TXQ_AC_VI,
[WME_AC_VO] = ATH_TXQ_AC_VO,
[IEEE80211_AC_BE] = ATH_TXQ_AC_BE,
[IEEE80211_AC_BK] = ATH_TXQ_AC_BK,
[IEEE80211_AC_VI] = ATH_TXQ_AC_VI,
[IEEE80211_AC_VO] = ATH_TXQ_AC_VO,
};
int axq_qnum, i;
@ -2319,6 +2319,8 @@ void ath_tx_edma_tasklet(struct ath_softc *sc)
ath_txq_lock(sc, txq);
TX_STAT_INC(txq->axq_qnum, txprocdesc);
if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
ath_txq_unlock(sc, txq);
return;
@ -2464,7 +2466,7 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
}
for (acno = 0, ac = &an->ac[acno];
acno < WME_NUM_AC; acno++, ac++) {
acno < IEEE80211_NUM_ACS; acno++, ac++) {
ac->sched = false;
ac->txq = sc->tx.txq_map[acno];
INIT_LIST_HEAD(&ac->tid_q);

View File

@ -28,11 +28,6 @@
#include "fwcmd.h"
#include "version.h"
#define MAKE_STR(symbol) #symbol
#define TO_STR(symbol) MAKE_STR(symbol)
#define CARL9170FW_API_VER_STR TO_STR(CARL9170FW_API_MAX_VER)
MODULE_VERSION(CARL9170FW_API_VER_STR ":" CARL9170FW_VERSION_GIT);
static const u8 otus_magic[4] = { OTUS_MAGIC };
static const void *carl9170_fw_find_desc(struct ar9170 *ar, const u8 descid[4],

View File

@ -796,7 +796,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
status.mactime += mactime;
if (low_mactime_now <= mactime)
status.mactime -= 0x10000;
status.flag |= RX_FLAG_MACTIME_MPDU;
status.flag |= RX_FLAG_MACTIME_START;
}
chanid = (chanstat & B43_RX_CHAN_ID) >> B43_RX_CHAN_ID_SHIFT;

View File

@ -557,7 +557,7 @@ void b43legacy_rx(struct b43legacy_wldev *dev,
status.mactime += mactime;
if (low_mactime_now <= mactime)
status.mactime -= 0x10000;
status.flag |= RX_FLAG_MACTIME_MPDU;
status.flag |= RX_FLAG_MACTIME_START;
}
chanid = (chanstat & B43legacy_RX_CHAN_ID) >>

View File

@ -55,13 +55,16 @@ config BRCMFMAC_USB
IEEE802.11n embedded FullMAC WLAN driver. Say Y if you want to
use the driver for an USB wireless card.
config BRCMISCAN
bool "Broadcom I-Scan (OBSOLETE)"
depends on BRCMFMAC
config BRCM_TRACING
bool "Broadcom device tracing"
depends on BRCMSMAC || BRCMFMAC
---help---
This option enables the I-Scan method. By default fullmac uses the
new E-Scan method which uses less memory in firmware and gives no
limitation on the number of scan results.
If you say Y here, the Broadcom wireless drivers will register
with ftrace to dump event information into the trace ringbuffer.
Tracing can be enabled at runtime to aid in debugging wireless
issues. This option adds a small amount of overhead when tracing
is disabled. If unsure, say Y to allow developers to better help
you when wireless problems occur.
config BRCMDBG
bool "Broadcom driver debug functions"

View File

@ -25,6 +25,7 @@ obj-$(CONFIG_BRCMFMAC) += brcmfmac.o
brcmfmac-objs += \
wl_cfg80211.o \
fwil.o \
fweh.o \
dhd_cdc.o \
dhd_common.o \
dhd_linux.o

View File

@ -42,7 +42,8 @@
#ifdef CONFIG_BRCMFMAC_SDIO_OOB
static irqreturn_t brcmf_sdio_irqhandler(int irq, void *dev_id)
{
struct brcmf_sdio_dev *sdiodev = dev_get_drvdata(dev_id);
struct brcmf_bus *bus_if = dev_get_drvdata(dev_id);
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
brcmf_dbg(INTR, "oob intr triggered\n");
@ -71,7 +72,7 @@ int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev)
brcmf_dbg(ERROR, "requesting irq %d\n", sdiodev->irq);
ret = request_irq(sdiodev->irq, brcmf_sdio_irqhandler,
sdiodev->irq_flags, "brcmf_oob_intr",
&sdiodev->func[1]->card->dev);
&sdiodev->func[1]->dev);
if (ret != 0)
return ret;
spin_lock_init(&sdiodev->irq_en_lock);
@ -84,6 +85,8 @@ int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev)
return ret;
sdiodev->irq_wake = true;
sdio_claim_host(sdiodev->func[1]);
/* must configure SDIO_CCCR_IENx to enable irq */
data = brcmf_sdio_regrb(sdiodev, SDIO_CCCR_IENx, &ret);
data |= 1 << SDIO_FUNC_1 | 1 << SDIO_FUNC_2 | 1;
@ -95,6 +98,8 @@ int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev)
data |= SDIO_SEPINT_ACT_HI;
brcmf_sdio_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, data, &ret);
sdio_release_host(sdiodev->func[1]);
return 0;
}
@ -102,14 +107,16 @@ int brcmf_sdio_intr_unregister(struct brcmf_sdio_dev *sdiodev)
{
brcmf_dbg(TRACE, "Entering\n");
sdio_claim_host(sdiodev->func[1]);
brcmf_sdio_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, 0, NULL);
brcmf_sdio_regwb(sdiodev, SDIO_CCCR_IENx, 0, NULL);
sdio_release_host(sdiodev->func[1]);
if (sdiodev->irq_wake) {
disable_irq_wake(sdiodev->irq);
sdiodev->irq_wake = false;
}
free_irq(sdiodev->irq, &sdiodev->func[1]->card->dev);
free_irq(sdiodev->irq, &sdiodev->func[1]->dev);
sdiodev->irq_en = false;
return 0;
@ -117,7 +124,8 @@ int brcmf_sdio_intr_unregister(struct brcmf_sdio_dev *sdiodev)
#else /* CONFIG_BRCMFMAC_SDIO_OOB */
static void brcmf_sdio_irqhandler(struct sdio_func *func)
{
struct brcmf_sdio_dev *sdiodev = dev_get_drvdata(&func->card->dev);
struct brcmf_bus *bus_if = dev_get_drvdata(&func->dev);
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
brcmf_dbg(INTR, "ib intr triggered\n");
@ -249,9 +257,7 @@ u8 brcmf_sdio_regrb(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)
int retval;
brcmf_dbg(INFO, "addr:0x%08x\n", addr);
sdio_claim_host(sdiodev->func[1]);
retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, false);
sdio_release_host(sdiodev->func[1]);
brcmf_dbg(INFO, "data:0x%02x\n", data);
if (ret)
@ -266,9 +272,7 @@ u32 brcmf_sdio_regrl(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)
int retval;
brcmf_dbg(INFO, "addr:0x%08x\n", addr);
sdio_claim_host(sdiodev->func[1]);
retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, false);
sdio_release_host(sdiodev->func[1]);
brcmf_dbg(INFO, "data:0x%08x\n", data);
if (ret)
@ -283,9 +287,7 @@ void brcmf_sdio_regwb(struct brcmf_sdio_dev *sdiodev, u32 addr,
int retval;
brcmf_dbg(INFO, "addr:0x%08x, data:0x%02x\n", addr, data);
sdio_claim_host(sdiodev->func[1]);
retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, true);
sdio_release_host(sdiodev->func[1]);
if (ret)
*ret = retval;
@ -297,9 +299,7 @@ void brcmf_sdio_regwl(struct brcmf_sdio_dev *sdiodev, u32 addr,
int retval;
brcmf_dbg(INFO, "addr:0x%08x, data:0x%08x\n", addr, data);
sdio_claim_host(sdiodev->func[1]);
retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, true);
sdio_release_host(sdiodev->func[1]);
if (ret)
*ret = retval;
@ -364,8 +364,6 @@ brcmf_sdcard_recv_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n",
fn, addr, pkt->len);
sdio_claim_host(sdiodev->func[1]);
width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
err = brcmf_sdcard_recv_prepare(sdiodev, fn, flags, width, &addr);
if (err)
@ -376,8 +374,6 @@ brcmf_sdcard_recv_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
fn, addr, pkt);
done:
sdio_release_host(sdiodev->func[1]);
return err;
}
@ -391,8 +387,6 @@ int brcmf_sdcard_recv_chain(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n",
fn, addr, pktq->qlen);
sdio_claim_host(sdiodev->func[1]);
width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
err = brcmf_sdcard_recv_prepare(sdiodev, fn, flags, width, &addr);
if (err)
@ -403,8 +397,6 @@ int brcmf_sdcard_recv_chain(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
pktq);
done:
sdio_release_host(sdiodev->func[1]);
return err;
}
@ -446,8 +438,6 @@ brcmf_sdcard_send_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
if (flags & SDIO_REQ_ASYNC)
return -ENOTSUPP;
sdio_claim_host(sdiodev->func[1]);
if (bar0 != sdiodev->sbwad) {
err = brcmf_sdcard_set_sbaddr_window(sdiodev, bar0);
if (err)
@ -467,8 +457,6 @@ brcmf_sdcard_send_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
addr, pkt);
done:
sdio_release_host(sdiodev->func[1]);
return err;
}
@ -510,10 +498,8 @@ int brcmf_sdcard_abort(struct brcmf_sdio_dev *sdiodev, uint fn)
brcmf_dbg(TRACE, "Enter\n");
/* issue abort cmd52 command through F0 */
sdio_claim_host(sdiodev->func[1]);
brcmf_sdioh_request_byte(sdiodev, SDIOH_WRITE, SDIO_FUNC_0,
SDIO_CCCR_ABORT, &t_func);
sdio_release_host(sdiodev->func[1]);
brcmf_dbg(TRACE, "Exit\n");
return 0;
@ -530,9 +516,6 @@ int brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
regs = SI_ENUM_BASE;
/* Report the BAR, to fix if needed */
sdiodev->sbwad = SI_ENUM_BASE;
/* try to attach to the target device */
sdiodev->bus = brcmf_sdbrcm_probe(regs, sdiodev);
if (!sdiodev->bus) {
@ -551,6 +534,8 @@ EXPORT_SYMBOL(brcmf_sdio_probe);
int brcmf_sdio_remove(struct brcmf_sdio_dev *sdiodev)
{
sdiodev->bus_if->state = BRCMF_BUS_DOWN;
if (sdiodev->bus) {
brcmf_sdbrcm_disconnect(sdiodev->bus);
sdiodev->bus = NULL;

View File

@ -372,9 +372,7 @@ static int brcmf_sdioh_enablefuncs(struct brcmf_sdio_dev *sdiodev)
}
/* Enable Function 1 */
sdio_claim_host(sdiodev->func[1]);
err_ret = sdio_enable_func(sdiodev->func[1]);
sdio_release_host(sdiodev->func[1]);
if (err_ret)
brcmf_dbg(ERROR, "Failed to enable F1 Err: 0x%08x\n", err_ret);
@ -393,16 +391,14 @@ int brcmf_sdioh_attach(struct brcmf_sdio_dev *sdiodev)
sdiodev->num_funcs = 2;
sdio_claim_host(sdiodev->func[1]);
err_ret = sdio_set_block_size(sdiodev->func[1], SDIO_FUNC1_BLOCKSIZE);
sdio_release_host(sdiodev->func[1]);
if (err_ret) {
brcmf_dbg(ERROR, "Failed to set F1 blocksize\n");
goto out;
}
sdio_claim_host(sdiodev->func[2]);
err_ret = sdio_set_block_size(sdiodev->func[2], SDIO_FUNC2_BLOCKSIZE);
sdio_release_host(sdiodev->func[2]);
if (err_ret) {
brcmf_dbg(ERROR, "Failed to set F2 blocksize\n");
goto out;
@ -411,6 +407,7 @@ int brcmf_sdioh_attach(struct brcmf_sdio_dev *sdiodev)
brcmf_sdioh_enablefuncs(sdiodev);
out:
sdio_release_host(sdiodev->func[1]);
brcmf_dbg(TRACE, "Done\n");
return err_ret;
}
@ -459,95 +456,106 @@ static inline int brcmf_sdio_getintrcfg(struct brcmf_sdio_dev *sdiodev)
#endif /* CONFIG_BRCMFMAC_SDIO_OOB */
static int brcmf_ops_sdio_probe(struct sdio_func *func,
const struct sdio_device_id *id)
const struct sdio_device_id *id)
{
int ret = 0;
int err;
struct brcmf_sdio_dev *sdiodev;
struct brcmf_bus *bus_if;
brcmf_dbg(TRACE, "Enter\n");
brcmf_dbg(TRACE, "func->class=%x\n", func->class);
brcmf_dbg(TRACE, "sdio_vendor: 0x%04x\n", func->vendor);
brcmf_dbg(TRACE, "sdio_device: 0x%04x\n", func->device);
brcmf_dbg(TRACE, "Function#: 0x%04x\n", func->num);
brcmf_dbg(TRACE, "Class=%x\n", func->class);
brcmf_dbg(TRACE, "sdio vendor ID: 0x%04x\n", func->vendor);
brcmf_dbg(TRACE, "sdio device ID: 0x%04x\n", func->device);
brcmf_dbg(TRACE, "Function#: %d\n", func->num);
if (func->num == 1) {
if (dev_get_drvdata(&func->card->dev)) {
brcmf_dbg(ERROR, "card private drvdata occupied\n");
return -ENXIO;
}
bus_if = kzalloc(sizeof(struct brcmf_bus), GFP_KERNEL);
if (!bus_if)
return -ENOMEM;
sdiodev = kzalloc(sizeof(struct brcmf_sdio_dev), GFP_KERNEL);
if (!sdiodev) {
kfree(bus_if);
return -ENOMEM;
}
sdiodev->func[0] = func;
sdiodev->func[1] = func;
sdiodev->bus_if = bus_if;
bus_if->bus_priv.sdio = sdiodev;
bus_if->type = SDIO_BUS;
bus_if->align = BRCMF_SDALIGN;
dev_set_drvdata(&func->card->dev, sdiodev);
/* Consume func num 1 but dont do anything with it. */
if (func->num == 1)
return 0;
atomic_set(&sdiodev->suspend, false);
init_waitqueue_head(&sdiodev->request_byte_wait);
init_waitqueue_head(&sdiodev->request_word_wait);
init_waitqueue_head(&sdiodev->request_chain_wait);
init_waitqueue_head(&sdiodev->request_buffer_wait);
/* Ignore anything but func 2 */
if (func->num != 2)
return -ENODEV;
bus_if = kzalloc(sizeof(struct brcmf_bus), GFP_KERNEL);
if (!bus_if)
return -ENOMEM;
sdiodev = kzalloc(sizeof(struct brcmf_sdio_dev), GFP_KERNEL);
if (!sdiodev) {
kfree(bus_if);
return -ENOMEM;
}
if (func->num == 2) {
sdiodev = dev_get_drvdata(&func->card->dev);
if ((!sdiodev) || (sdiodev->func[1]->card != func->card))
return -ENODEV;
sdiodev->func[0] = func->card->sdio_func[0];
sdiodev->func[1] = func->card->sdio_func[0];
sdiodev->func[2] = func;
ret = brcmf_sdio_getintrcfg(sdiodev);
if (ret)
return ret;
sdiodev->func[2] = func;
sdiodev->bus_if = bus_if;
bus_if->bus_priv.sdio = sdiodev;
bus_if->align = BRCMF_SDALIGN;
dev_set_drvdata(&func->dev, bus_if);
dev_set_drvdata(&sdiodev->func[1]->dev, bus_if);
sdiodev->dev = &sdiodev->func[1]->dev;
bus_if = sdiodev->bus_if;
sdiodev->dev = &func->dev;
dev_set_drvdata(&func->dev, bus_if);
atomic_set(&sdiodev->suspend, false);
init_waitqueue_head(&sdiodev->request_byte_wait);
init_waitqueue_head(&sdiodev->request_word_wait);
init_waitqueue_head(&sdiodev->request_chain_wait);
init_waitqueue_head(&sdiodev->request_buffer_wait);
err = brcmf_sdio_getintrcfg(sdiodev);
if (err)
goto fail;
brcmf_dbg(TRACE, "F2 found, calling brcmf_sdio_probe...\n");
ret = brcmf_sdio_probe(sdiodev);
brcmf_dbg(TRACE, "F2 found, calling brcmf_sdio_probe...\n");
err = brcmf_sdio_probe(sdiodev);
if (err) {
brcmf_dbg(ERROR, "F2 error, probe failed %d...\n", err);
goto fail;
}
brcmf_dbg(TRACE, "F2 init completed...\n");
return 0;
return ret;
fail:
dev_set_drvdata(&func->dev, NULL);
dev_set_drvdata(&sdiodev->func[1]->dev, NULL);
kfree(sdiodev);
kfree(bus_if);
return err;
}
static void brcmf_ops_sdio_remove(struct sdio_func *func)
{
struct brcmf_bus *bus_if;
struct brcmf_sdio_dev *sdiodev;
brcmf_dbg(TRACE, "Enter\n");
brcmf_dbg(INFO, "func->class=%x\n", func->class);
brcmf_dbg(INFO, "sdio_vendor: 0x%04x\n", func->vendor);
brcmf_dbg(INFO, "sdio_device: 0x%04x\n", func->device);
brcmf_dbg(INFO, "Function#: 0x%04x\n", func->num);
if (func->num == 2) {
bus_if = dev_get_drvdata(&func->dev);
brcmf_dbg(TRACE, "Enter\n");
brcmf_dbg(TRACE, "sdio vendor ID: 0x%04x\n", func->vendor);
brcmf_dbg(TRACE, "sdio device ID: 0x%04x\n", func->device);
brcmf_dbg(TRACE, "Function: %d\n", func->num);
if (func->num != 1 && func->num != 2)
return;
bus_if = dev_get_drvdata(&func->dev);
if (bus_if) {
sdiodev = bus_if->bus_priv.sdio;
brcmf_dbg(TRACE, "F2 found, calling brcmf_sdio_remove...\n");
brcmf_sdio_remove(sdiodev);
dev_set_drvdata(&func->card->dev, NULL);
dev_set_drvdata(&func->dev, NULL);
dev_set_drvdata(&sdiodev->func[1]->dev, NULL);
dev_set_drvdata(&sdiodev->func[2]->dev, NULL);
kfree(bus_if);
kfree(sdiodev);
}
brcmf_dbg(TRACE, "Exit\n");
}
#ifdef CONFIG_PM_SLEEP
static int brcmf_sdio_suspend(struct device *dev)
{
mmc_pm_flag_t sdio_flags;
struct sdio_func *func = dev_to_sdio_func(dev);
struct brcmf_sdio_dev *sdiodev = dev_get_drvdata(&func->card->dev);
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
int ret = 0;
brcmf_dbg(TRACE, "\n");
@ -573,8 +581,8 @@ static int brcmf_sdio_suspend(struct device *dev)
static int brcmf_sdio_resume(struct device *dev)
{
struct sdio_func *func = dev_to_sdio_func(dev);
struct brcmf_sdio_dev *sdiodev = dev_get_drvdata(&func->card->dev);
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
brcmf_sdio_wdtmr_enable(sdiodev, true);
atomic_set(&sdiodev->suspend, false);

View File

@ -23,6 +23,8 @@
#define BRCMF_VERSION_STR "4.218.248.5"
#include "fweh.h"
/*******************************************************************************
* IO codes that are interpreted by dongle firmware
******************************************************************************/
@ -38,8 +40,11 @@
#define BRCMF_C_GET_SSID 25
#define BRCMF_C_SET_SSID 26
#define BRCMF_C_GET_CHANNEL 29
#define BRCMF_C_SET_CHANNEL 30
#define BRCMF_C_GET_SRL 31
#define BRCMF_C_SET_SRL 32
#define BRCMF_C_GET_LRL 33
#define BRCMF_C_SET_LRL 34
#define BRCMF_C_GET_RADIO 37
#define BRCMF_C_SET_RADIO 38
#define BRCMF_C_GET_PHYTYPE 39
@ -58,6 +63,7 @@
#define BRCMF_C_SET_COUNTRY 84
#define BRCMF_C_GET_PM 85
#define BRCMF_C_SET_PM 86
#define BRCMF_C_GET_CURR_RATESET 114
#define BRCMF_C_GET_AP 117
#define BRCMF_C_SET_AP 118
#define BRCMF_C_GET_RSSI 127
@ -65,6 +71,7 @@
#define BRCMF_C_SET_WSEC 134
#define BRCMF_C_GET_PHY_NOISE 135
#define BRCMF_C_GET_BSS_INFO 136
#define BRCMF_C_GET_PHYLIST 180
#define BRCMF_C_SET_SCAN_CHANNEL_TIME 185
#define BRCMF_C_SET_SCAN_UNASSOC_TIME 187
#define BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON 201
@ -100,29 +107,8 @@
#define BRCMF_SCAN_PARAMS_COUNT_MASK 0x0000ffff
#define BRCMF_SCAN_PARAMS_NSSID_SHIFT 16
#define BRCMF_SCAN_ACTION_START 1
#define BRCMF_SCAN_ACTION_CONTINUE 2
#define WL_SCAN_ACTION_ABORT 3
#define BRCMF_ISCAN_REQ_VERSION 1
/* brcmf_iscan_results status values */
#define BRCMF_SCAN_RESULTS_SUCCESS 0
#define BRCMF_SCAN_RESULTS_PARTIAL 1
#define BRCMF_SCAN_RESULTS_PENDING 2
#define BRCMF_SCAN_RESULTS_ABORTED 3
#define BRCMF_SCAN_RESULTS_NO_MEM 4
/* Indicates this key is using soft encrypt */
#define WL_SOFT_KEY (1 << 0)
/* primary (ie tx) key */
#define BRCMF_PRIMARY_KEY (1 << 1)
/* Reserved for backward compat */
#define WL_KF_RES_4 (1 << 4)
/* Reserved for backward compat */
#define WL_KF_RES_5 (1 << 5)
/* Indicates a group key for a IBSS PEER */
#define WL_IBSS_PEER_GROUP_KEY (1 << 6)
/* For supporting multiple interfaces */
#define BRCMF_MAX_IFS 16
@ -130,10 +116,6 @@
#define DOT11_BSSTYPE_ANY 2
#define DOT11_MAX_DEFAULT_KEYS 4
#define BRCMF_EVENT_MSG_LINK 0x01
#define BRCMF_EVENT_MSG_FLUSHTXQ 0x02
#define BRCMF_EVENT_MSG_GROUP 0x04
#define BRCMF_ESCAN_REQ_VERSION 1
#define WLC_BSS_RSSI_ON_CHANNEL 0x0002
@ -141,108 +123,6 @@
#define BRCMF_MAXRATES_IN_SET 16 /* max # of rates in rateset */
#define BRCMF_STA_ASSOC 0x10 /* Associated */
struct brcmf_event_msg {
__be16 version;
__be16 flags;
__be32 event_type;
__be32 status;
__be32 reason;
__be32 auth_type;
__be32 datalen;
u8 addr[ETH_ALEN];
char ifname[IFNAMSIZ];
u8 ifidx;
u8 bsscfgidx;
} __packed;
struct brcm_ethhdr {
u16 subtype;
u16 length;
u8 version;
u8 oui[3];
u16 usr_subtype;
} __packed;
struct brcmf_event {
struct ethhdr eth;
struct brcm_ethhdr hdr;
struct brcmf_event_msg msg;
} __packed;
/* event codes sent by the dongle to this driver */
#define BRCMF_E_SET_SSID 0
#define BRCMF_E_JOIN 1
#define BRCMF_E_START 2
#define BRCMF_E_AUTH 3
#define BRCMF_E_AUTH_IND 4
#define BRCMF_E_DEAUTH 5
#define BRCMF_E_DEAUTH_IND 6
#define BRCMF_E_ASSOC 7
#define BRCMF_E_ASSOC_IND 8
#define BRCMF_E_REASSOC 9
#define BRCMF_E_REASSOC_IND 10
#define BRCMF_E_DISASSOC 11
#define BRCMF_E_DISASSOC_IND 12
#define BRCMF_E_QUIET_START 13
#define BRCMF_E_QUIET_END 14
#define BRCMF_E_BEACON_RX 15
#define BRCMF_E_LINK 16
#define BRCMF_E_MIC_ERROR 17
#define BRCMF_E_NDIS_LINK 18
#define BRCMF_E_ROAM 19
#define BRCMF_E_TXFAIL 20
#define BRCMF_E_PMKID_CACHE 21
#define BRCMF_E_RETROGRADE_TSF 22
#define BRCMF_E_PRUNE 23
#define BRCMF_E_AUTOAUTH 24
#define BRCMF_E_EAPOL_MSG 25
#define BRCMF_E_SCAN_COMPLETE 26
#define BRCMF_E_ADDTS_IND 27
#define BRCMF_E_DELTS_IND 28
#define BRCMF_E_BCNSENT_IND 29
#define BRCMF_E_BCNRX_MSG 30
#define BRCMF_E_BCNLOST_MSG 31
#define BRCMF_E_ROAM_PREP 32
#define BRCMF_E_PFN_NET_FOUND 33
#define BRCMF_E_PFN_NET_LOST 34
#define BRCMF_E_RESET_COMPLETE 35
#define BRCMF_E_JOIN_START 36
#define BRCMF_E_ROAM_START 37
#define BRCMF_E_ASSOC_START 38
#define BRCMF_E_IBSS_ASSOC 39
#define BRCMF_E_RADIO 40
#define BRCMF_E_PSM_WATCHDOG 41
#define BRCMF_E_PROBREQ_MSG 44
#define BRCMF_E_SCAN_CONFIRM_IND 45
#define BRCMF_E_PSK_SUP 46
#define BRCMF_E_COUNTRY_CODE_CHANGED 47
#define BRCMF_E_EXCEEDED_MEDIUM_TIME 48
#define BRCMF_E_ICV_ERROR 49
#define BRCMF_E_UNICAST_DECODE_ERROR 50
#define BRCMF_E_MULTICAST_DECODE_ERROR 51
#define BRCMF_E_TRACE 52
#define BRCMF_E_IF 54
#define BRCMF_E_RSSI 56
#define BRCMF_E_PFN_SCAN_COMPLETE 57
#define BRCMF_E_EXTLOG_MSG 58
#define BRCMF_E_ACTION_FRAME 59
#define BRCMF_E_ACTION_FRAME_COMPLETE 60
#define BRCMF_E_PRE_ASSOC_IND 61
#define BRCMF_E_PRE_REASSOC_IND 62
#define BRCMF_E_CHANNEL_ADOPTED 63
#define BRCMF_E_AP_STARTED 64
#define BRCMF_E_DFS_AP_STOP 65
#define BRCMF_E_DFS_AP_RESUME 66
#define BRCMF_E_RESERVED1 67
#define BRCMF_E_RESERVED2 68
#define BRCMF_E_ESCAN_RESULT 69
#define BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE 70
#define BRCMF_E_DCS_REQUEST 73
#define BRCMF_E_FIFO_CREDIT_MAP 74
#define BRCMF_E_LAST 75
#define BRCMF_E_STATUS_SUCCESS 0
#define BRCMF_E_STATUS_FAIL 1
#define BRCMF_E_STATUS_TIMEOUT 2
@ -403,7 +283,7 @@ struct brcm_rateset_le {
/* # rates in this set */
__le32 count;
/* rates in 500kbps units w/hi bit set if basic */
u8 rates[WL_NUMRATES];
u8 rates[BRCMF_MAXRATES_IN_SET];
};
struct brcmf_ssid {
@ -452,14 +332,6 @@ struct brcmf_scan_params_le {
__le16 channel_list[1]; /* list of chanspecs */
};
/* incremental scan struct */
struct brcmf_iscan_params_le {
__le32 version;
__le16 action;
__le16 scan_duration;
struct brcmf_scan_params_le params_le;
};
struct brcmf_scan_results {
u32 buflen;
u32 version;
@ -467,12 +339,6 @@ struct brcmf_scan_results {
struct brcmf_bss_info_le bss_info_le[];
};
struct brcmf_scan_results_le {
__le32 buflen;
__le32 version;
__le32 count;
};
struct brcmf_escan_params_le {
__le32 version;
__le16 action;
@ -508,23 +374,6 @@ struct brcmf_join_params {
struct brcmf_assoc_params_le params_le;
};
/* incremental scan results struct */
struct brcmf_iscan_results {
union {
u32 status;
__le32 status_le;
};
union {
struct brcmf_scan_results results;
struct brcmf_scan_results_le results_le;
};
};
/* size of brcmf_iscan_results not including variable length array */
#define BRCMF_ISCAN_RESULTS_FIXED_SIZE \
(sizeof(struct brcmf_scan_results) + \
offsetof(struct brcmf_iscan_results, results))
struct brcmf_wsec_key {
u32 index; /* key index */
u32 len; /* key length */
@ -661,10 +510,11 @@ struct brcmf_pub {
struct mutex proto_block;
unsigned char proto_buf[BRCMF_DCMD_MAXLEN];
struct work_struct setmacaddr_work;
struct work_struct multicast_work;
u8 macvalue[ETH_ALEN];
atomic_t pend_8021x_cnt;
wait_queue_head_t pend_8021x_wait;
struct brcmf_fweh_info fweh;
#ifdef DEBUG
struct dentry *dbgfs_dir;
#endif
@ -701,6 +551,8 @@ struct brcmf_if {
struct brcmf_cfg80211_vif *vif;
struct net_device *ndev;
struct net_device_stats stats;
struct work_struct setmacaddr_work;
struct work_struct multicast_work;
int idx;
s32 bssidx;
u8 mac_addr[ETH_ALEN];
@ -714,9 +566,6 @@ static inline s32 brcmf_ndev_bssidx(struct net_device *ndev)
extern const struct bcmevent_name bcmevent_names[];
extern uint brcmf_c_mkiovar(char *name, char *data, uint datalen,
char *buf, uint len);
extern int brcmf_netdev_wait_pend8021x(struct net_device *ndev);
/* Return pointer to interface name */
@ -728,14 +577,9 @@ extern int brcmf_proto_cdc_query_dcmd(struct brcmf_pub *drvr, int ifidx,
extern int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
void *buf, uint len);
extern int brcmf_ifname2idx(struct brcmf_pub *drvr, char *name);
extern int brcmf_c_host_event(struct brcmf_pub *drvr, int *idx,
void *pktdata, struct brcmf_event_msg *,
void **data_ptr);
extern int brcmf_net_attach(struct brcmf_if *ifp);
extern struct brcmf_if *brcmf_add_if(struct device *dev, int ifidx, s32 bssidx,
char *name, u8 *mac_addr);
extern struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx,
s32 bssidx, char *name, u8 *mac_addr);
extern void brcmf_del_if(struct brcmf_pub *drvr, int ifidx);
#endif /* _BRCMF_H_ */

View File

@ -45,7 +45,6 @@ struct brcmf_bus_dcmd {
/* interface structure between common and bus layer */
struct brcmf_bus {
u8 type; /* bus type */
union {
struct brcmf_sdio_dev *sdio;
struct brcmf_usbdev *usb;
@ -85,7 +84,7 @@ extern bool brcmf_c_prec_enq(struct device *dev, struct pktq *q,
struct sk_buff *pkt, int prec);
/* Receive frame for delivery to OS. Callee disposes of rxp. */
extern void brcmf_rx_frame(struct device *dev, int ifidx,
extern void brcmf_rx_frame(struct device *dev, u8 ifidx,
struct sk_buff_head *rxlist);
static inline void brcmf_rx_packet(struct device *dev, int ifidx,
struct sk_buff *pkt)

View File

@ -23,8 +23,6 @@
#include <linux/types.h>
#include <linux/netdevice.h>
#include <linux/sched.h>
#include <defs.h>
#include <brcmu_utils.h>
#include <brcmu_wifi.h>
@ -277,76 +275,6 @@ done:
return ret;
}
int
brcmf_proto_dcmd(struct brcmf_pub *drvr, int ifidx, struct brcmf_dcmd *dcmd,
int len)
{
struct brcmf_proto *prot = drvr->prot;
int ret = -1;
if (drvr->bus_if->state == BRCMF_BUS_DOWN) {
brcmf_dbg(ERROR, "bus is down. we have nothing to do.\n");
return ret;
}
mutex_lock(&drvr->proto_block);
brcmf_dbg(TRACE, "Enter\n");
if (len > BRCMF_DCMD_MAXLEN)
goto done;
if (prot->pending == true) {
brcmf_dbg(TRACE, "CDC packet is pending!!!! cmd=0x%x (%lu) lastcmd=0x%x (%lu)\n",
dcmd->cmd, (unsigned long)dcmd->cmd, prot->lastcmd,
(unsigned long)prot->lastcmd);
if (dcmd->cmd == BRCMF_C_SET_VAR ||
dcmd->cmd == BRCMF_C_GET_VAR)
brcmf_dbg(TRACE, "iovar cmd=%s\n", (char *)dcmd->buf);
goto done;
}
prot->pending = true;
prot->lastcmd = dcmd->cmd;
if (dcmd->set)
ret = brcmf_proto_cdc_set_dcmd(drvr, ifidx, dcmd->cmd,
dcmd->buf, len);
else {
ret = brcmf_proto_cdc_query_dcmd(drvr, ifidx, dcmd->cmd,
dcmd->buf, len);
if (ret > 0)
dcmd->used = ret -
sizeof(struct brcmf_proto_cdc_dcmd);
}
if (ret >= 0)
ret = 0;
else {
struct brcmf_proto_cdc_dcmd *msg = &prot->msg;
/* len == needed when set/query fails from dongle */
dcmd->needed = le32_to_cpu(msg->len);
}
/* Intercept the wme_dp dongle cmd here */
if (!ret && dcmd->cmd == BRCMF_C_SET_VAR &&
!strcmp(dcmd->buf, "wme_dp")) {
int slen;
__le32 val = 0;
slen = strlen("wme_dp") + 1;
if (len >= (int)(slen + sizeof(int)))
memcpy(&val, (char *)dcmd->buf + slen, sizeof(int));
drvr->wme_dp = (u8) le32_to_cpu(val);
}
prot->pending = false;
done:
mutex_unlock(&drvr->proto_block);
return ret;
}
static bool pkt_sum_needed(struct sk_buff *skb)
{
return skb->ip_summed == CHECKSUM_PARTIAL;

View File

@ -18,10 +18,7 @@
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/sched.h>
#include <linux/netdevice.h>
#include <asm/unaligned.h>
#include <defs.h>
#include <brcmu_wifi.h>
#include <brcmu_utils.h>
#include "dhd.h"
@ -30,9 +27,6 @@
#include "dhd_dbg.h"
#include "fwil.h"
#define BRCM_OUI "\x00\x10\x18"
#define DOT11_OUI_LEN 3
#define BCMILCP_BCM_SUBTYPE_EVENT 1
#define PKTFILTER_BUF_SIZE 128
#define BRCMF_ARPOL_MODE 0xb /* agent|snoop|peer_autoreply */
#define BRCMF_DEFAULT_BCN_TIMEOUT 3
@ -40,12 +34,6 @@
#define BRCMF_DEFAULT_SCAN_UNASSOC_TIME 40
#define BRCMF_DEFAULT_PACKET_FILTER "100 0 0 0 0x01 0x00"
#define MSGTRACE_VERSION 1
#define BRCMF_PKT_FILTER_FIXED_LEN offsetof(struct brcmf_pkt_filter_le, u)
#define BRCMF_PKT_FILTER_PATTERN_FIXED_LEN \
offsetof(struct brcmf_pkt_filter_pattern_le, mask_and_pattern)
#ifdef DEBUG
static const char brcmf_version[] =
"Dongle Host Driver, version " BRCMF_VERSION_STR "\nCompiled on "
@ -55,43 +43,6 @@ static const char brcmf_version[] =
"Dongle Host Driver, version " BRCMF_VERSION_STR;
#endif
/* Message trace header */
struct msgtrace_hdr {
u8 version;
u8 spare;
__be16 len; /* Len of the trace */
__be32 seqnum; /* Sequence number of message. Useful
* if the messsage has been lost
* because of DMA error or a bus reset
* (ex: SDIO Func2)
*/
__be32 discarded_bytes; /* Number of discarded bytes because of
trace overflow */
__be32 discarded_printf; /* Number of discarded printf
because of trace overflow */
} __packed;
uint
brcmf_c_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen)
{
uint len;
len = strlen(name) + 1;
if ((len + datalen) > buflen)
return 0;
strncpy(buf, name, buflen);
/* append data onto the end of the name string */
if (data && datalen) {
memcpy(&buf[len], data, datalen);
len += datalen;
}
return len;
}
bool brcmf_c_prec_enq(struct device *dev, struct pktq *q,
struct sk_buff *pkt, int prec)
@ -143,405 +94,6 @@ bool brcmf_c_prec_enq(struct device *dev, struct pktq *q,
return p != NULL;
}
#ifdef DEBUG
static void
brcmf_c_show_host_event(struct brcmf_event_msg *event, void *event_data)
{
uint i, status, reason;
bool group = false, flush_txq = false, link = false;
char *auth_str, *event_name;
unsigned char *buf;
char err_msg[256], eabuf[ETHER_ADDR_STR_LEN];
static struct {
uint event;
char *event_name;
} event_names[] = {
{
BRCMF_E_SET_SSID, "SET_SSID"}, {
BRCMF_E_JOIN, "JOIN"}, {
BRCMF_E_START, "START"}, {
BRCMF_E_AUTH, "AUTH"}, {
BRCMF_E_AUTH_IND, "AUTH_IND"}, {
BRCMF_E_DEAUTH, "DEAUTH"}, {
BRCMF_E_DEAUTH_IND, "DEAUTH_IND"}, {
BRCMF_E_ASSOC, "ASSOC"}, {
BRCMF_E_ASSOC_IND, "ASSOC_IND"}, {
BRCMF_E_REASSOC, "REASSOC"}, {
BRCMF_E_REASSOC_IND, "REASSOC_IND"}, {
BRCMF_E_DISASSOC, "DISASSOC"}, {
BRCMF_E_DISASSOC_IND, "DISASSOC_IND"}, {
BRCMF_E_QUIET_START, "START_QUIET"}, {
BRCMF_E_QUIET_END, "END_QUIET"}, {
BRCMF_E_BEACON_RX, "BEACON_RX"}, {
BRCMF_E_LINK, "LINK"}, {
BRCMF_E_MIC_ERROR, "MIC_ERROR"}, {
BRCMF_E_NDIS_LINK, "NDIS_LINK"}, {
BRCMF_E_ROAM, "ROAM"}, {
BRCMF_E_TXFAIL, "TXFAIL"}, {
BRCMF_E_PMKID_CACHE, "PMKID_CACHE"}, {
BRCMF_E_RETROGRADE_TSF, "RETROGRADE_TSF"}, {
BRCMF_E_PRUNE, "PRUNE"}, {
BRCMF_E_AUTOAUTH, "AUTOAUTH"}, {
BRCMF_E_EAPOL_MSG, "EAPOL_MSG"}, {
BRCMF_E_SCAN_COMPLETE, "SCAN_COMPLETE"}, {
BRCMF_E_ADDTS_IND, "ADDTS_IND"}, {
BRCMF_E_DELTS_IND, "DELTS_IND"}, {
BRCMF_E_BCNSENT_IND, "BCNSENT_IND"}, {
BRCMF_E_BCNRX_MSG, "BCNRX_MSG"}, {
BRCMF_E_BCNLOST_MSG, "BCNLOST_MSG"}, {
BRCMF_E_ROAM_PREP, "ROAM_PREP"}, {
BRCMF_E_PFN_NET_FOUND, "PNO_NET_FOUND"}, {
BRCMF_E_PFN_NET_LOST, "PNO_NET_LOST"}, {
BRCMF_E_RESET_COMPLETE, "RESET_COMPLETE"}, {
BRCMF_E_JOIN_START, "JOIN_START"}, {
BRCMF_E_ROAM_START, "ROAM_START"}, {
BRCMF_E_ASSOC_START, "ASSOC_START"}, {
BRCMF_E_IBSS_ASSOC, "IBSS_ASSOC"}, {
BRCMF_E_RADIO, "RADIO"}, {
BRCMF_E_PSM_WATCHDOG, "PSM_WATCHDOG"}, {
BRCMF_E_PROBREQ_MSG, "PROBREQ_MSG"}, {
BRCMF_E_SCAN_CONFIRM_IND, "SCAN_CONFIRM_IND"}, {
BRCMF_E_PSK_SUP, "PSK_SUP"}, {
BRCMF_E_COUNTRY_CODE_CHANGED, "COUNTRY_CODE_CHANGED"}, {
BRCMF_E_EXCEEDED_MEDIUM_TIME, "EXCEEDED_MEDIUM_TIME"}, {
BRCMF_E_ICV_ERROR, "ICV_ERROR"}, {
BRCMF_E_UNICAST_DECODE_ERROR, "UNICAST_DECODE_ERROR"}, {
BRCMF_E_MULTICAST_DECODE_ERROR, "MULTICAST_DECODE_ERROR"}, {
BRCMF_E_TRACE, "TRACE"}, {
BRCMF_E_ACTION_FRAME, "ACTION FRAME"}, {
BRCMF_E_ACTION_FRAME_COMPLETE, "ACTION FRAME TX COMPLETE"}, {
BRCMF_E_IF, "IF"}, {
BRCMF_E_RSSI, "RSSI"}, {
BRCMF_E_PFN_SCAN_COMPLETE, "SCAN_COMPLETE"}, {
BRCMF_E_ESCAN_RESULT, "ESCAN_RESULT"}
};
uint event_type, flags, auth_type, datalen;
static u32 seqnum_prev;
struct msgtrace_hdr hdr;
u32 nblost;
char *s, *p;
event_type = be32_to_cpu(event->event_type);
flags = be16_to_cpu(event->flags);
status = be32_to_cpu(event->status);
reason = be32_to_cpu(event->reason);
auth_type = be32_to_cpu(event->auth_type);
datalen = be32_to_cpu(event->datalen);
/* debug dump of event messages */
sprintf(eabuf, "%pM", event->addr);
event_name = "UNKNOWN";
for (i = 0; i < ARRAY_SIZE(event_names); i++) {
if (event_names[i].event == event_type)
event_name = event_names[i].event_name;
}
brcmf_dbg(EVENT, "EVENT: %s, event ID = %d\n", event_name, event_type);
brcmf_dbg(EVENT, "flags 0x%04x, status %d, reason %d, auth_type %d MAC %s\n",
flags, status, reason, auth_type, eabuf);
if (flags & BRCMF_EVENT_MSG_LINK)
link = true;
if (flags & BRCMF_EVENT_MSG_GROUP)
group = true;
if (flags & BRCMF_EVENT_MSG_FLUSHTXQ)
flush_txq = true;
switch (event_type) {
case BRCMF_E_START:
case BRCMF_E_DEAUTH:
case BRCMF_E_DISASSOC:
brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s\n", event_name, eabuf);
break;
case BRCMF_E_ASSOC_IND:
case BRCMF_E_REASSOC_IND:
brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s\n", event_name, eabuf);
break;
case BRCMF_E_ASSOC:
case BRCMF_E_REASSOC:
if (status == BRCMF_E_STATUS_SUCCESS)
brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, SUCCESS\n",
event_name, eabuf);
else if (status == BRCMF_E_STATUS_TIMEOUT)
brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, TIMEOUT\n",
event_name, eabuf);
else if (status == BRCMF_E_STATUS_FAIL)
brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, FAILURE, reason %d\n",
event_name, eabuf, (int)reason);
else
brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, unexpected status %d\n",
event_name, eabuf, (int)status);
break;
case BRCMF_E_DEAUTH_IND:
case BRCMF_E_DISASSOC_IND:
brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, reason %d\n",
event_name, eabuf, (int)reason);
break;
case BRCMF_E_AUTH:
case BRCMF_E_AUTH_IND:
if (auth_type == WLAN_AUTH_OPEN)
auth_str = "Open System";
else if (auth_type == WLAN_AUTH_SHARED_KEY)
auth_str = "Shared Key";
else {
sprintf(err_msg, "AUTH unknown: %d", (int)auth_type);
auth_str = err_msg;
}
if (event_type == BRCMF_E_AUTH_IND)
brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, %s\n",
event_name, eabuf, auth_str);
else if (status == BRCMF_E_STATUS_SUCCESS)
brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, %s, SUCCESS\n",
event_name, eabuf, auth_str);
else if (status == BRCMF_E_STATUS_TIMEOUT)
brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, %s, TIMEOUT\n",
event_name, eabuf, auth_str);
else if (status == BRCMF_E_STATUS_FAIL) {
brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, %s, FAILURE, reason %d\n",
event_name, eabuf, auth_str, (int)reason);
}
break;
case BRCMF_E_JOIN:
case BRCMF_E_ROAM:
case BRCMF_E_SET_SSID:
if (status == BRCMF_E_STATUS_SUCCESS)
brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s\n",
event_name, eabuf);
else if (status == BRCMF_E_STATUS_FAIL)
brcmf_dbg(EVENT, "MACEVENT: %s, failed\n", event_name);
else if (status == BRCMF_E_STATUS_NO_NETWORKS)
brcmf_dbg(EVENT, "MACEVENT: %s, no networks found\n",
event_name);
else
brcmf_dbg(EVENT, "MACEVENT: %s, unexpected status %d\n",
event_name, (int)status);
break;
case BRCMF_E_BEACON_RX:
if (status == BRCMF_E_STATUS_SUCCESS)
brcmf_dbg(EVENT, "MACEVENT: %s, SUCCESS\n", event_name);
else if (status == BRCMF_E_STATUS_FAIL)
brcmf_dbg(EVENT, "MACEVENT: %s, FAIL\n", event_name);
else
brcmf_dbg(EVENT, "MACEVENT: %s, status %d\n",
event_name, status);
break;
case BRCMF_E_LINK:
brcmf_dbg(EVENT, "MACEVENT: %s %s\n",
event_name, link ? "UP" : "DOWN");
break;
case BRCMF_E_MIC_ERROR:
brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, Group %d, Flush %d\n",
event_name, eabuf, group, flush_txq);
break;
case BRCMF_E_ICV_ERROR:
case BRCMF_E_UNICAST_DECODE_ERROR:
case BRCMF_E_MULTICAST_DECODE_ERROR:
brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s\n", event_name, eabuf);
break;
case BRCMF_E_TXFAIL:
brcmf_dbg(EVENT, "MACEVENT: %s, RA %s\n", event_name, eabuf);
break;
case BRCMF_E_SCAN_COMPLETE:
case BRCMF_E_PMKID_CACHE:
brcmf_dbg(EVENT, "MACEVENT: %s\n", event_name);
break;
case BRCMF_E_ESCAN_RESULT:
brcmf_dbg(EVENT, "MACEVENT: %s\n", event_name);
datalen = 0;
break;
case BRCMF_E_PFN_NET_FOUND:
case BRCMF_E_PFN_NET_LOST:
case BRCMF_E_PFN_SCAN_COMPLETE:
brcmf_dbg(EVENT, "PNOEVENT: %s\n", event_name);
break;
case BRCMF_E_PSK_SUP:
case BRCMF_E_PRUNE:
brcmf_dbg(EVENT, "MACEVENT: %s, status %d, reason %d\n",
event_name, (int)status, (int)reason);
break;
case BRCMF_E_TRACE:
buf = (unsigned char *) event_data;
memcpy(&hdr, buf, sizeof(struct msgtrace_hdr));
if (hdr.version != MSGTRACE_VERSION) {
brcmf_dbg(ERROR,
"MACEVENT: %s [unsupported version --> brcmf"
" version:%d dongle version:%d]\n",
event_name, MSGTRACE_VERSION, hdr.version);
/* Reset datalen to avoid display below */
datalen = 0;
break;
}
/* There are 2 bytes available at the end of data */
*(buf + sizeof(struct msgtrace_hdr)
+ be16_to_cpu(hdr.len)) = '\0';
if (be32_to_cpu(hdr.discarded_bytes)
|| be32_to_cpu(hdr.discarded_printf))
brcmf_dbg(ERROR,
"WLC_E_TRACE: [Discarded traces in dongle -->"
" discarded_bytes %d discarded_printf %d]\n",
be32_to_cpu(hdr.discarded_bytes),
be32_to_cpu(hdr.discarded_printf));
nblost = be32_to_cpu(hdr.seqnum) - seqnum_prev - 1;
if (nblost > 0)
brcmf_dbg(ERROR, "WLC_E_TRACE: [Event lost --> seqnum "
" %d nblost %d\n", be32_to_cpu(hdr.seqnum),
nblost);
seqnum_prev = be32_to_cpu(hdr.seqnum);
/* Display the trace buffer. Advance from \n to \n to
* avoid display big
* printf (issue with Linux printk )
*/
p = (char *)&buf[sizeof(struct msgtrace_hdr)];
while ((s = strstr(p, "\n")) != NULL) {
*s = '\0';
pr_debug("%s\n", p);
p = s + 1;
}
pr_debug("%s\n", p);
/* Reset datalen to avoid display below */
datalen = 0;
break;
case BRCMF_E_RSSI:
brcmf_dbg(EVENT, "MACEVENT: %s %d\n",
event_name, be32_to_cpu(*((__be32 *)event_data)));
break;
default:
brcmf_dbg(EVENT,
"MACEVENT: %s %d, MAC %s, status %d, reason %d, "
"auth %d\n", event_name, event_type, eabuf,
(int)status, (int)reason, (int)auth_type);
break;
}
/* show any appended data */
brcmf_dbg_hex_dump(datalen, event_data, datalen, "Received data");
}
#endif /* DEBUG */
int
brcmf_c_host_event(struct brcmf_pub *drvr, int *ifidx, void *pktdata,
struct brcmf_event_msg *event, void **data_ptr)
{
/* check whether packet is a BRCM event pkt */
struct brcmf_event *pvt_data = (struct brcmf_event *) pktdata;
struct brcmf_if_event *ifevent;
struct brcmf_if *ifp;
char *event_data;
u32 type, status;
u16 flags;
int evlen;
if (memcmp(BRCM_OUI, &pvt_data->hdr.oui[0], DOT11_OUI_LEN)) {
brcmf_dbg(ERROR, "mismatched OUI, bailing\n");
return -EBADE;
}
/* BRCM event pkt may be unaligned - use xxx_ua to load user_subtype. */
if (get_unaligned_be16(&pvt_data->hdr.usr_subtype) !=
BCMILCP_BCM_SUBTYPE_EVENT) {
brcmf_dbg(ERROR, "mismatched subtype, bailing\n");
return -EBADE;
}
*data_ptr = &pvt_data[1];
event_data = *data_ptr;
/* memcpy since BRCM event pkt may be unaligned. */
memcpy(event, &pvt_data->msg, sizeof(struct brcmf_event_msg));
type = get_unaligned_be32(&event->event_type);
flags = get_unaligned_be16(&event->flags);
status = get_unaligned_be32(&event->status);
evlen = get_unaligned_be32(&event->datalen) +
sizeof(struct brcmf_event);
switch (type) {
case BRCMF_E_IF:
ifevent = (struct brcmf_if_event *) event_data;
brcmf_dbg(TRACE, "if event\n");
if (ifevent->ifidx > 0 && ifevent->ifidx < BRCMF_MAX_IFS) {
if (ifevent->action == BRCMF_E_IF_ADD) {
ifp = brcmf_add_if(drvr->dev, ifevent->ifidx,
ifevent->bssidx,
event->ifname,
pvt_data->eth.h_dest);
if (IS_ERR(ifp))
return PTR_ERR(ifp);
brcmf_net_attach(ifp);
} else {
brcmf_del_if(drvr, ifevent->ifidx);
}
} else {
brcmf_dbg(ERROR, "Invalid ifidx %d for %s\n",
ifevent->ifidx, event->ifname);
}
/* send up the if event: btamp user needs it */
*ifidx = brcmf_ifname2idx(drvr, event->ifname);
break;
/* These are what external supplicant/authenticator wants */
case BRCMF_E_LINK:
case BRCMF_E_ASSOC_IND:
case BRCMF_E_REASSOC_IND:
case BRCMF_E_DISASSOC_IND:
case BRCMF_E_MIC_ERROR:
default:
/* Fall through: this should get _everything_ */
*ifidx = brcmf_ifname2idx(drvr, event->ifname);
brcmf_dbg(TRACE, "MAC event %d, flags %x, status %x\n",
type, flags, status);
/* put it back to BRCMF_E_NDIS_LINK */
if (type == BRCMF_E_NDIS_LINK) {
u32 temp1;
__be32 temp2;
temp1 = get_unaligned_be32(&event->event_type);
brcmf_dbg(TRACE, "Converted to WLC_E_LINK type %d\n",
temp1);
temp2 = cpu_to_be32(BRCMF_E_NDIS_LINK);
memcpy((void *)(&pvt_data->msg.event_type), &temp2,
sizeof(pvt_data->msg.event_type));
}
break;
}
#ifdef DEBUG
if (BRCMF_EVENT_ON())
brcmf_c_show_host_event(event, event_data);
#endif /* DEBUG */
return 0;
}
/* Convert user's input in hex pattern to byte-size mask */
static int brcmf_c_pattern_atoh(char *src, char *dst)
{
@ -686,8 +238,8 @@ static void brcmf_c_pktfilter_offload_set(struct brcmf_if *ifp, char *arg)
}
pkt_filter->u.pattern.size_bytes = cpu_to_le32(mask_size);
buf_len = sizeof(*pkt_filter);
buf_len -= sizeof(pkt_filter->u.pattern.mask_and_pattern);
buf_len = offsetof(struct brcmf_pkt_filter_le,
u.pattern.mask_and_pattern);
buf_len += mask_size + pattern_size;
err = brcmf_fil_iovar_data_set(ifp, "pkt_filter_add", pkt_filter,

View File

@ -14,18 +14,12 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/debugfs.h>
#include <linux/if_ether.h>
#include <linux/if.h>
#include <linux/netdevice.h>
#include <linux/ieee80211.h>
#include <linux/module.h>
#include <linux/netdevice.h>
#include <defs.h>
#include <brcmu_wifi.h>
#include <brcmu_utils.h>
#include "dhd.h"
#include "dhd_bus.h"
#include "dhd_dbg.h"
static struct dentry *root_folder;

View File

@ -27,11 +27,11 @@
#define BRCMF_HDRS_VAL 0x0040
#define BRCMF_BYTES_VAL 0x0080
#define BRCMF_INTR_VAL 0x0100
#define BRCMF_GLOM_VAL 0x0400
#define BRCMF_EVENT_VAL 0x0800
#define BRCMF_BTA_VAL 0x1000
#define BRCMF_ISCAN_VAL 0x2000
#define BRCMF_FIL_VAL 0x4000
#define BRCMF_GLOM_VAL 0x0200
#define BRCMF_EVENT_VAL 0x0400
#define BRCMF_BTA_VAL 0x0800
#define BRCMF_FIL_VAL 0x1000
#define BRCMF_USB_VAL 0x2000
#if defined(DEBUG)

View File

@ -16,27 +16,11 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/slab.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/mmc/sdio_func.h>
#include <linux/random.h>
#include <linux/spinlock.h>
#include <linux/ethtool.h>
#include <linux/fcntl.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/hardirq.h>
#include <linux/mutex.h>
#include <linux/wait.h>
#include <linux/module.h>
#include <net/cfg80211.h>
#include <net/rtnetlink.h>
#include <defs.h>
#include <brcmu_utils.h>
#include <brcmu_wifi.h>
@ -45,35 +29,19 @@
#include "dhd_proto.h"
#include "dhd_dbg.h"
#include "wl_cfg80211.h"
#include "fwil.h"
MODULE_AUTHOR("Broadcom Corporation");
MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN fullmac driver.");
MODULE_SUPPORTED_DEVICE("Broadcom 802.11n WLAN fullmac cards");
MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver.");
MODULE_SUPPORTED_DEVICE("Broadcom 802.11 WLAN fullmac cards");
MODULE_LICENSE("Dual BSD/GPL");
#define MAX_WAIT_FOR_8021X_TX 50 /* msecs */
/* Error bits */
int brcmf_msg_level = BRCMF_ERROR_VAL;
module_param(brcmf_msg_level, int, 0);
int brcmf_ifname2idx(struct brcmf_pub *drvr, char *name)
{
int i = BRCMF_MAX_IFS;
struct brcmf_if *ifp;
if (name == NULL || *name == '\0')
return 0;
while (--i > 0) {
ifp = drvr->iflist[i];
if (ifp && !strncmp(ifp->ndev->name, name, IFNAMSIZ))
break;
}
brcmf_dbg(TRACE, "return idx %d for \"%s\"\n", i, name);
return i; /* default - the primary interface */
}
char *brcmf_ifname(struct brcmf_pub *drvr, int ifidx)
{
@ -95,38 +63,33 @@ char *brcmf_ifname(struct brcmf_pub *drvr, int ifidx)
static void _brcmf_set_multicast_list(struct work_struct *work)
{
struct brcmf_if *ifp;
struct net_device *ndev;
struct netdev_hw_addr *ha;
u32 dcmd_value, cnt;
u32 cmd_value, cnt;
__le32 cnt_le;
__le32 dcmd_le_value;
struct brcmf_dcmd dcmd;
char *buf, *bufp;
uint buflen;
int ret;
u32 buflen;
s32 err;
struct brcmf_pub *drvr = container_of(work, struct brcmf_pub,
multicast_work);
brcmf_dbg(TRACE, "enter\n");
ndev = drvr->iflist[0]->ndev;
cnt = netdev_mc_count(ndev);
ifp = container_of(work, struct brcmf_if, multicast_work);
ndev = ifp->ndev;
/* Determine initial value of allmulti flag */
dcmd_value = (ndev->flags & IFF_ALLMULTI) ? true : false;
cmd_value = (ndev->flags & IFF_ALLMULTI) ? true : false;
/* Send down the multicast list first. */
buflen = sizeof("mcast_list") + sizeof(cnt) + (cnt * ETH_ALEN);
bufp = buf = kmalloc(buflen, GFP_ATOMIC);
if (!bufp)
cnt = netdev_mc_count(ndev);
buflen = sizeof(cnt) + (cnt * ETH_ALEN);
buf = kmalloc(buflen, GFP_ATOMIC);
if (!buf)
return;
strcpy(bufp, "mcast_list");
bufp += strlen("mcast_list") + 1;
bufp = buf;
cnt_le = cpu_to_le32(cnt);
memcpy(bufp, &cnt_le, sizeof(cnt));
memcpy(bufp, &cnt_le, sizeof(cnt_le));
bufp += sizeof(cnt_le);
netdev_for_each_mc_addr(ha, ndev) {
@ -137,129 +100,66 @@ static void _brcmf_set_multicast_list(struct work_struct *work)
cnt--;
}
memset(&dcmd, 0, sizeof(dcmd));
dcmd.cmd = BRCMF_C_SET_VAR;
dcmd.buf = buf;
dcmd.len = buflen;
dcmd.set = true;
ret = brcmf_proto_dcmd(drvr, 0, &dcmd, dcmd.len);
if (ret < 0) {
brcmf_dbg(ERROR, "%s: set mcast_list failed, cnt %d\n",
brcmf_ifname(drvr, 0), cnt);
dcmd_value = cnt ? true : dcmd_value;
err = brcmf_fil_iovar_data_set(ifp, "mcast_list", buf, buflen);
if (err < 0) {
brcmf_dbg(ERROR, "Setting mcast_list failed, %d\n", err);
cmd_value = cnt ? true : cmd_value;
}
kfree(buf);
/* Now send the allmulti setting. This is based on the setting in the
/*
* Now send the allmulti setting. This is based on the setting in the
* net_device flags, but might be modified above to be turned on if we
* were trying to set some addresses and dongle rejected it...
*/
err = brcmf_fil_iovar_int_set(ifp, "allmulti", cmd_value);
if (err < 0)
brcmf_dbg(ERROR, "Setting allmulti failed, %d\n", err);
buflen = sizeof("allmulti") + sizeof(dcmd_value);
buf = kmalloc(buflen, GFP_ATOMIC);
if (!buf)
return;
dcmd_le_value = cpu_to_le32(dcmd_value);
if (!brcmf_c_mkiovar
("allmulti", (void *)&dcmd_le_value,
sizeof(dcmd_le_value), buf, buflen)) {
brcmf_dbg(ERROR, "%s: mkiovar failed for allmulti, datalen %d buflen %u\n",
brcmf_ifname(drvr, 0),
(int)sizeof(dcmd_value), buflen);
kfree(buf);
return;
}
memset(&dcmd, 0, sizeof(dcmd));
dcmd.cmd = BRCMF_C_SET_VAR;
dcmd.buf = buf;
dcmd.len = buflen;
dcmd.set = true;
ret = brcmf_proto_dcmd(drvr, 0, &dcmd, dcmd.len);
if (ret < 0) {
brcmf_dbg(ERROR, "%s: set allmulti %d failed\n",
brcmf_ifname(drvr, 0),
le32_to_cpu(dcmd_le_value));
}
kfree(buf);
/* Finally, pick up the PROMISC flag as well, like the NIC
driver does */
dcmd_value = (ndev->flags & IFF_PROMISC) ? true : false;
dcmd_le_value = cpu_to_le32(dcmd_value);
memset(&dcmd, 0, sizeof(dcmd));
dcmd.cmd = BRCMF_C_SET_PROMISC;
dcmd.buf = &dcmd_le_value;
dcmd.len = sizeof(dcmd_le_value);
dcmd.set = true;
ret = brcmf_proto_dcmd(drvr, 0, &dcmd, dcmd.len);
if (ret < 0) {
brcmf_dbg(ERROR, "%s: set promisc %d failed\n",
brcmf_ifname(drvr, 0),
le32_to_cpu(dcmd_le_value));
}
/*Finally, pick up the PROMISC flag */
cmd_value = (ndev->flags & IFF_PROMISC) ? true : false;
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PROMISC, cmd_value);
if (err < 0)
brcmf_dbg(ERROR, "Setting BRCMF_C_SET_PROMISC failed, %d\n",
err);
}
static void
_brcmf_set_mac_address(struct work_struct *work)
{
char buf[32];
struct brcmf_dcmd dcmd;
int ret;
struct brcmf_pub *drvr = container_of(work, struct brcmf_pub,
setmacaddr_work);
struct brcmf_if *ifp;
s32 err;
brcmf_dbg(TRACE, "enter\n");
if (!brcmf_c_mkiovar("cur_etheraddr", (char *)drvr->macvalue,
ETH_ALEN, buf, 32)) {
brcmf_dbg(ERROR, "%s: mkiovar failed for cur_etheraddr\n",
brcmf_ifname(drvr, 0));
return;
ifp = container_of(work, struct brcmf_if, setmacaddr_work);
err = brcmf_fil_iovar_data_set(ifp, "cur_etheraddr", ifp->mac_addr,
ETH_ALEN);
if (err < 0) {
brcmf_dbg(ERROR, "Setting cur_etheraddr failed, %d\n", err);
} else {
brcmf_dbg(TRACE, "MAC address updated to %pM\n",
ifp->mac_addr);
memcpy(ifp->ndev->dev_addr, ifp->mac_addr, ETH_ALEN);
}
memset(&dcmd, 0, sizeof(dcmd));
dcmd.cmd = BRCMF_C_SET_VAR;
dcmd.buf = buf;
dcmd.len = 32;
dcmd.set = true;
ret = brcmf_proto_dcmd(drvr, 0, &dcmd, dcmd.len);
if (ret < 0)
brcmf_dbg(ERROR, "%s: set cur_etheraddr failed\n",
brcmf_ifname(drvr, 0));
else
memcpy(drvr->iflist[0]->ndev->dev_addr,
drvr->macvalue, ETH_ALEN);
return;
}
static int brcmf_netdev_set_mac_address(struct net_device *ndev, void *addr)
{
struct brcmf_if *ifp = netdev_priv(ndev);
struct brcmf_pub *drvr = ifp->drvr;
struct sockaddr *sa = (struct sockaddr *)addr;
memcpy(&drvr->macvalue, sa->sa_data, ETH_ALEN);
schedule_work(&drvr->setmacaddr_work);
memcpy(&ifp->mac_addr, sa->sa_data, ETH_ALEN);
schedule_work(&ifp->setmacaddr_work);
return 0;
}
static void brcmf_netdev_set_multicast_list(struct net_device *ndev)
{
struct brcmf_if *ifp = netdev_priv(ndev);
struct brcmf_pub *drvr = ifp->drvr;
schedule_work(&drvr->multicast_work);
schedule_work(&ifp->multicast_work);
}
static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev)
@ -272,7 +172,7 @@ static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev)
/* Reject if down */
if (!drvr->bus_if->drvr_up ||
(drvr->bus_if->state == BRCMF_BUS_DOWN)) {
(drvr->bus_if->state != BRCMF_BUS_DATA)) {
brcmf_dbg(ERROR, "xmit rejected drvup=%d state=%d\n",
drvr->bus_if->drvr_up,
drvr->bus_if->state);
@ -350,32 +250,13 @@ void brcmf_txflowblock(struct device *dev, bool state)
}
}
static int brcmf_host_event(struct brcmf_pub *drvr, int *ifidx,
void *pktdata, struct brcmf_event_msg *event,
void **data)
{
int bcmerror = 0;
bcmerror = brcmf_c_host_event(drvr, ifidx, pktdata, event, data);
if (bcmerror != 0)
return bcmerror;
if (drvr->iflist[*ifidx]->ndev)
brcmf_cfg80211_event(drvr->iflist[*ifidx]->ndev,
event, *data);
return bcmerror;
}
void brcmf_rx_frame(struct device *dev, int ifidx,
void brcmf_rx_frame(struct device *dev, u8 ifidx,
struct sk_buff_head *skb_list)
{
unsigned char *eth;
uint len;
void *data;
struct sk_buff *skb, *pnext;
struct brcmf_if *ifp;
struct brcmf_event_msg event;
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_pub *drvr = bus_if->drvr;
@ -422,10 +303,7 @@ void brcmf_rx_frame(struct device *dev, int ifidx,
skb_pull(skb, ETH_HLEN);
/* Process special event packets and then discard them */
if (ntohs(skb->protocol) == ETH_P_LINK_CTL)
brcmf_host_event(drvr, &ifidx,
skb_mac_header(skb),
&event, &data);
brcmf_fweh_process_skb(drvr, skb, &ifidx);
if (drvr->iflist[ifidx]) {
ifp = drvr->iflist[ifidx];
@ -461,9 +339,11 @@ void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success)
eh = (struct ethhdr *)(txp->data);
type = ntohs(eh->h_proto);
if (type == ETH_P_PAE)
if (type == ETH_P_PAE) {
atomic_dec(&drvr->pend_8021x_cnt);
if (waitqueue_active(&drvr->pend_8021x_wait))
wake_up(&drvr->pend_8021x_wait);
}
}
static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev)
@ -487,83 +367,26 @@ static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev)
return &ifp->stats;
}
/* Retrieve current toe component enables, which are kept
as a bitmap in toe_ol iovar */
static int brcmf_toe_get(struct brcmf_pub *drvr, int ifidx, u32 *toe_ol)
/*
* Set current toe component enables in toe_ol iovar,
* and set toe global enable iovar
*/
static int brcmf_toe_set(struct brcmf_if *ifp, u32 toe_ol)
{
struct brcmf_dcmd dcmd;
__le32 toe_le;
char buf[32];
int ret;
s32 err;
memset(&dcmd, 0, sizeof(dcmd));
dcmd.cmd = BRCMF_C_GET_VAR;
dcmd.buf = buf;
dcmd.len = (uint) sizeof(buf);
dcmd.set = false;
strcpy(buf, "toe_ol");
ret = brcmf_proto_dcmd(drvr, ifidx, &dcmd, dcmd.len);
if (ret < 0) {
/* Check for older dongle image that doesn't support toe_ol */
if (ret == -EIO) {
brcmf_dbg(ERROR, "%s: toe not supported by device\n",
brcmf_ifname(drvr, ifidx));
return -EOPNOTSUPP;
}
brcmf_dbg(INFO, "%s: could not get toe_ol: ret=%d\n",
brcmf_ifname(drvr, ifidx), ret);
return ret;
err = brcmf_fil_iovar_int_set(ifp, "toe_ol", toe_ol);
if (err < 0) {
brcmf_dbg(ERROR, "Setting toe_ol failed, %d\n", err);
return err;
}
memcpy(&toe_le, buf, sizeof(u32));
*toe_ol = le32_to_cpu(toe_le);
return 0;
}
err = brcmf_fil_iovar_int_set(ifp, "toe", (toe_ol != 0));
if (err < 0)
brcmf_dbg(ERROR, "Setting toe failed, %d\n", err);
/* Set current toe component enables in toe_ol iovar,
and set toe global enable iovar */
static int brcmf_toe_set(struct brcmf_pub *drvr, int ifidx, u32 toe_ol)
{
struct brcmf_dcmd dcmd;
char buf[32];
int ret;
__le32 toe_le = cpu_to_le32(toe_ol);
return err;
memset(&dcmd, 0, sizeof(dcmd));
dcmd.cmd = BRCMF_C_SET_VAR;
dcmd.buf = buf;
dcmd.len = (uint) sizeof(buf);
dcmd.set = true;
/* Set toe_ol as requested */
strcpy(buf, "toe_ol");
memcpy(&buf[sizeof("toe_ol")], &toe_le, sizeof(u32));
ret = brcmf_proto_dcmd(drvr, ifidx, &dcmd, dcmd.len);
if (ret < 0) {
brcmf_dbg(ERROR, "%s: could not set toe_ol: ret=%d\n",
brcmf_ifname(drvr, ifidx), ret);
return ret;
}
/* Enable toe globally only if any components are enabled. */
toe_le = cpu_to_le32(toe_ol != 0);
strcpy(buf, "toe");
memcpy(&buf[sizeof("toe")], &toe_le, sizeof(u32));
ret = brcmf_proto_dcmd(drvr, ifidx, &dcmd, dcmd.len);
if (ret < 0) {
brcmf_dbg(ERROR, "%s: could not set toe: ret=%d\n",
brcmf_ifname(drvr, ifidx), ret);
return ret;
}
return 0;
}
static void brcmf_ethtool_get_drvinfo(struct net_device *ndev,
@ -581,8 +404,9 @@ static const struct ethtool_ops brcmf_ethtool_ops = {
.get_drvinfo = brcmf_ethtool_get_drvinfo,
};
static int brcmf_ethtool(struct brcmf_pub *drvr, void __user *uaddr)
static int brcmf_ethtool(struct brcmf_if *ifp, void __user *uaddr)
{
struct brcmf_pub *drvr = ifp->drvr;
struct ethtool_drvinfo info;
char drvname[sizeof(info.driver)];
u32 cmd;
@ -633,7 +457,7 @@ static int brcmf_ethtool(struct brcmf_pub *drvr, void __user *uaddr)
/* Get toe offload components from dongle */
case ETHTOOL_GRXCSUM:
case ETHTOOL_GTXCSUM:
ret = brcmf_toe_get(drvr, 0, &toe_cmpnt);
ret = brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_cmpnt);
if (ret < 0)
return ret;
@ -654,7 +478,7 @@ static int brcmf_ethtool(struct brcmf_pub *drvr, void __user *uaddr)
return -EFAULT;
/* Read the current settings, update and write back */
ret = brcmf_toe_get(drvr, 0, &toe_cmpnt);
ret = brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_cmpnt);
if (ret < 0)
return ret;
@ -666,18 +490,16 @@ static int brcmf_ethtool(struct brcmf_pub *drvr, void __user *uaddr)
else
toe_cmpnt &= ~csum_dir;
ret = brcmf_toe_set(drvr, 0, toe_cmpnt);
ret = brcmf_toe_set(ifp, toe_cmpnt);
if (ret < 0)
return ret;
/* If setting TX checksum mode, tell Linux the new mode */
if (cmd == ETHTOOL_STXCSUM) {
if (edata.data)
drvr->iflist[0]->ndev->features |=
NETIF_F_IP_CSUM;
ifp->ndev->features |= NETIF_F_IP_CSUM;
else
drvr->iflist[0]->ndev->features &=
~NETIF_F_IP_CSUM;
ifp->ndev->features &= ~NETIF_F_IP_CSUM;
}
break;
@ -701,7 +523,7 @@ static int brcmf_netdev_ioctl_entry(struct net_device *ndev, struct ifreq *ifr,
return -1;
if (cmd == SIOCETHTOOL)
return brcmf_ethtool(drvr, ifr->ifr_data);
return brcmf_ethtool(ifp, ifr->ifr_data);
return -EOPNOTSUPP;
}
@ -712,10 +534,12 @@ static int brcmf_netdev_stop(struct net_device *ndev)
struct brcmf_pub *drvr = ifp->drvr;
brcmf_dbg(TRACE, "Enter\n");
brcmf_cfg80211_down(drvr->config);
if (drvr->bus_if->drvr_up == 0)
return 0;
brcmf_cfg80211_down(ndev);
/* Set state and stop OS transmissions */
drvr->bus_if->drvr_up = false;
netif_stop_queue(ndev);
@ -730,38 +554,35 @@ static int brcmf_netdev_open(struct net_device *ndev)
struct brcmf_bus *bus_if = drvr->bus_if;
u32 toe_ol;
s32 ret = 0;
uint up = 0;
brcmf_dbg(TRACE, "ifidx %d\n", ifp->idx);
if (ifp->idx == 0) { /* do it only for primary eth0 */
/* If bus is not ready, can't continue */
if (bus_if->state != BRCMF_BUS_DATA) {
brcmf_dbg(ERROR, "failed bus is not ready\n");
return -EAGAIN;
}
atomic_set(&drvr->pend_8021x_cnt, 0);
memcpy(ndev->dev_addr, drvr->mac, ETH_ALEN);
/* Get current TOE mode from dongle */
if (brcmf_toe_get(drvr, ifp->idx, &toe_ol) >= 0
&& (toe_ol & TOE_TX_CSUM_OL) != 0)
drvr->iflist[ifp->idx]->ndev->features |=
NETIF_F_IP_CSUM;
else
drvr->iflist[ifp->idx]->ndev->features &=
~NETIF_F_IP_CSUM;
/* If bus is not ready, can't continue */
if (bus_if->state != BRCMF_BUS_DATA) {
brcmf_dbg(ERROR, "failed bus is not ready\n");
return -EAGAIN;
}
atomic_set(&drvr->pend_8021x_cnt, 0);
memcpy(ndev->dev_addr, drvr->mac, ETH_ALEN);
/* Get current TOE mode from dongle */
if (brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_ol) >= 0
&& (toe_ol & TOE_TX_CSUM_OL) != 0)
drvr->iflist[ifp->idx]->ndev->features |=
NETIF_F_IP_CSUM;
else
drvr->iflist[ifp->idx]->ndev->features &=
~NETIF_F_IP_CSUM;
/* make sure RF is ready for work */
brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_UP, (char *)&up, sizeof(up));
brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
/* Allow transmit calls */
netif_start_queue(ndev);
drvr->bus_if->drvr_up = true;
if (brcmf_cfg80211_up(drvr->config)) {
if (brcmf_cfg80211_up(ndev)) {
brcmf_dbg(ERROR, "failed to bring up cfg80211\n");
return -1;
}
@ -779,39 +600,38 @@ static const struct net_device_ops brcmf_netdev_ops_pri = {
.ndo_set_rx_mode = brcmf_netdev_set_multicast_list
};
static const struct net_device_ops brcmf_netdev_ops_virt = {
.ndo_open = brcmf_cfg80211_up,
.ndo_stop = brcmf_cfg80211_down,
.ndo_get_stats = brcmf_netdev_get_stats,
.ndo_do_ioctl = brcmf_netdev_ioctl_entry,
.ndo_start_xmit = brcmf_netdev_start_xmit,
.ndo_set_mac_address = brcmf_netdev_set_mac_address,
.ndo_set_rx_mode = brcmf_netdev_set_multicast_list
};
int brcmf_net_attach(struct brcmf_if *ifp)
{
struct brcmf_pub *drvr = ifp->drvr;
struct net_device *ndev;
u8 temp_addr[ETH_ALEN];
brcmf_dbg(TRACE, "ifidx %d\n", ifp->idx);
brcmf_dbg(TRACE, "ifidx %d mac %pM\n", ifp->idx, ifp->mac_addr);
ndev = ifp->ndev;
ndev = drvr->iflist[ifp->idx]->ndev;
ndev->netdev_ops = &brcmf_netdev_ops_pri;
/*
* determine mac address to use
*/
if (is_valid_ether_addr(ifp->mac_addr))
memcpy(temp_addr, ifp->mac_addr, ETH_ALEN);
/* set appropriate operations */
if (!ifp->idx)
ndev->netdev_ops = &brcmf_netdev_ops_pri;
else
memcpy(temp_addr, drvr->mac, ETH_ALEN);
ndev->netdev_ops = &brcmf_netdev_ops_virt;
if (ifp->idx == 1) {
brcmf_dbg(TRACE, "ACCESS POINT MAC:\n");
/* ACCESSPOINT INTERFACE CASE */
temp_addr[0] |= 0X02; /* set bit 2 ,
- Locally Administered address */
}
ndev->hard_header_len = ETH_HLEN + drvr->hdrlen;
ndev->ethtool_ops = &brcmf_ethtool_ops;
drvr->rxsz = ndev->mtu + ndev->hard_header_len +
drvr->hdrlen;
memcpy(ndev->dev_addr, temp_addr, ETH_ALEN);
/* set the mac address */
memcpy(ndev->dev_addr, ifp->mac_addr, ETH_ALEN);
if (register_netdev(ndev) != 0) {
brcmf_dbg(ERROR, "couldn't register the net device\n");
@ -824,17 +644,15 @@ int brcmf_net_attach(struct brcmf_if *ifp)
fail:
ndev->netdev_ops = NULL;
free_netdev(ndev);
return -EBADE;
}
struct brcmf_if *brcmf_add_if(struct device *dev, int ifidx, s32 bssidx,
char *name, u8 *mac_addr)
struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx, s32 bssidx,
char *name, u8 *addr_mask)
{
struct brcmf_if *ifp;
struct net_device *ndev;
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_pub *drvr = bus_if->drvr;
int i;
brcmf_dbg(TRACE, "idx %d\n", ifidx);
@ -844,12 +662,17 @@ struct brcmf_if *brcmf_add_if(struct device *dev, int ifidx, s32 bssidx,
* in case we missed the BRCMF_E_IF_DEL event.
*/
if (ifp) {
brcmf_dbg(ERROR, "ERROR: netdev:%s already exists, try free & unregister\n",
brcmf_dbg(ERROR, "ERROR: netdev:%s already exists\n",
ifp->ndev->name);
netif_stop_queue(ifp->ndev);
unregister_netdev(ifp->ndev);
free_netdev(ifp->ndev);
drvr->iflist[ifidx] = NULL;
if (ifidx) {
netif_stop_queue(ifp->ndev);
unregister_netdev(ifp->ndev);
free_netdev(ifp->ndev);
drvr->iflist[ifidx] = NULL;
} else {
brcmf_dbg(ERROR, "ignore IF event\n");
return ERR_PTR(-EINVAL);
}
}
/* Allocate netdev, including space for private structure */
@ -865,11 +688,16 @@ struct brcmf_if *brcmf_add_if(struct device *dev, int ifidx, s32 bssidx,
drvr->iflist[ifidx] = ifp;
ifp->idx = ifidx;
ifp->bssidx = bssidx;
if (mac_addr != NULL)
memcpy(&ifp->mac_addr, mac_addr, ETH_ALEN);
brcmf_dbg(TRACE, " ==== pid:%x, net_device for if:%s created ===\n",
current->pid, ifp->ndev->name);
INIT_WORK(&ifp->setmacaddr_work, _brcmf_set_mac_address);
INIT_WORK(&ifp->multicast_work, _brcmf_set_multicast_list);
if (addr_mask != NULL)
for (i = 0; i < ETH_ALEN; i++)
ifp->mac_addr[i] = drvr->mac[i] ^ addr_mask[i];
brcmf_dbg(TRACE, " ==== pid:%x, if:%s (%pM) created ===\n",
current->pid, ifp->ndev->name, ifp->mac_addr);
return ifp;
}
@ -896,6 +724,9 @@ void brcmf_del_if(struct brcmf_pub *drvr, int ifidx)
netif_stop_queue(ifp->ndev);
}
cancel_work_sync(&ifp->setmacaddr_work);
cancel_work_sync(&ifp->multicast_work);
unregister_netdev(ifp->ndev);
drvr->iflist[ifidx] = NULL;
if (ifidx == 0)
@ -934,11 +765,13 @@ int brcmf_attach(uint bus_hdrlen, struct device *dev)
goto fail;
}
INIT_WORK(&drvr->setmacaddr_work, _brcmf_set_mac_address);
INIT_WORK(&drvr->multicast_work, _brcmf_set_multicast_list);
/* attach firmware event handler */
brcmf_fweh_attach(drvr);
INIT_LIST_HEAD(&drvr->bus_if->dcmd_list);
init_waitqueue_head(&drvr->pend_8021x_wait);
return ret;
fail:
@ -964,7 +797,7 @@ int brcmf_bus_start(struct device *dev)
}
/* add primary networking interface */
ifp = brcmf_add_if(dev, 0, 0, "wlan%d", NULL);
ifp = brcmf_add_if(drvr, 0, 0, "wlan%d", NULL);
if (IS_ERR(ifp))
return PTR_ERR(ifp);
@ -974,15 +807,25 @@ int brcmf_bus_start(struct device *dev)
/* Bus is ready, do any initialization */
ret = brcmf_c_preinit_dcmds(ifp);
if (ret < 0)
return ret;
goto fail;
drvr->config = brcmf_cfg80211_attach(drvr);
if (drvr->config == NULL)
return -ENOMEM;
if (drvr->config == NULL) {
ret = -ENOMEM;
goto fail;
}
ret = brcmf_fweh_activate_events(ifp);
if (ret < 0)
goto fail;
ret = brcmf_net_attach(ifp);
fail:
if (ret < 0) {
brcmf_dbg(ERROR, "brcmf_net_attach failed");
brcmf_dbg(ERROR, "failed: %d\n", ret);
if (drvr->config)
brcmf_cfg80211_detach(drvr->config);
free_netdev(drvr->iflist[0]->ndev);
drvr->iflist[0] = NULL;
return ret;
}
@ -1011,6 +854,11 @@ void brcmf_detach(struct device *dev)
brcmf_dbg(TRACE, "Enter\n");
if (drvr == NULL)
return;
/* stop firmware event handling */
brcmf_fweh_detach(drvr);
/* make sure primary interface removed last */
for (i = BRCMF_MAX_IFS-1; i > -1; i--)
@ -1020,8 +868,6 @@ void brcmf_detach(struct device *dev)
brcmf_bus_detach(drvr);
if (drvr->prot) {
cancel_work_sync(&drvr->setmacaddr_work);
cancel_work_sync(&drvr->multicast_work);
brcmf_proto_detach(drvr);
}
@ -1035,26 +881,19 @@ static int brcmf_get_pend_8021x_cnt(struct brcmf_pub *drvr)
return atomic_read(&drvr->pend_8021x_cnt);
}
#define MAX_WAIT_FOR_8021X_TX 10
int brcmf_netdev_wait_pend8021x(struct net_device *ndev)
{
struct brcmf_if *ifp = netdev_priv(ndev);
struct brcmf_pub *drvr = ifp->drvr;
int timeout = 10 * HZ / 1000;
int ntimes = MAX_WAIT_FOR_8021X_TX;
int pend = brcmf_get_pend_8021x_cnt(drvr);
int err;
while (ntimes && pend) {
if (pend) {
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(timeout);
set_current_state(TASK_RUNNING);
ntimes--;
}
pend = brcmf_get_pend_8021x_cnt(drvr);
}
return pend;
err = wait_event_timeout(drvr->pend_8021x_wait,
!brcmf_get_pend_8021x_cnt(drvr),
msecs_to_jiffies(MAX_WAIT_FOR_8021X_TX));
WARN_ON(!err);
return !err;
}
static void brcmf_driver_init(struct work_struct *work)

View File

@ -36,14 +36,7 @@ extern void brcmf_proto_stop(struct brcmf_pub *drvr);
extern void brcmf_proto_hdrpush(struct brcmf_pub *, int ifidx,
struct sk_buff *txp);
/* Use protocol to issue command to dongle */
extern int brcmf_proto_dcmd(struct brcmf_pub *drvr, int ifidx,
struct brcmf_dcmd *dcmd, int len);
/* Sets dongle media info (drv_version, mac address). */
extern int brcmf_c_preinit_dcmds(struct brcmf_if *ifp);
extern int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx,
uint cmd, void *buf, uint len);
#endif /* _BRCMF_PROTO_H_ */

View File

@ -533,9 +533,11 @@ struct brcmf_sdio {
u8 *rxbuf; /* Buffer for receiving control packets */
uint rxblen; /* Allocated length of rxbuf */
u8 *rxctl; /* Aligned pointer into rxbuf */
u8 *rxctl_orig; /* pointer for freeing rxctl */
u8 *databuf; /* Buffer for receiving big glom packet */
u8 *dataptr; /* Aligned pointer into databuf */
uint rxlen; /* Length of valid data in buffer */
spinlock_t rxctl_lock; /* protection lock for ctrl frame resources */
u8 sdpcm_ver; /* Bus protocol reported by dongle */
@ -582,8 +584,6 @@ struct brcmf_sdio {
struct list_head dpc_tsklst;
spinlock_t dpc_tl_lock;
struct semaphore sdsem;
const struct firmware *firmware;
u32 fw_ptr;
@ -1037,9 +1037,9 @@ static void brcmf_sdbrcm_free_glom(struct brcmf_sdio *bus)
}
}
static bool brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header,
struct brcmf_sdio_read *rd,
enum brcmf_sdio_frmtype type)
static int brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header,
struct brcmf_sdio_read *rd,
enum brcmf_sdio_frmtype type)
{
u16 len, checksum;
u8 rx_seq, fc, tx_seq_max;
@ -1054,26 +1054,26 @@ static bool brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header,
/* All zero means no more to read */
if (!(len | checksum)) {
bus->rxpending = false;
return false;
return -ENODATA;
}
if ((u16)(~(len ^ checksum))) {
brcmf_dbg(ERROR, "HW header checksum error\n");
bus->sdcnt.rx_badhdr++;
brcmf_sdbrcm_rxfail(bus, false, false);
return false;
return -EIO;
}
if (len < SDPCM_HDRLEN) {
brcmf_dbg(ERROR, "HW header length error\n");
return false;
return -EPROTO;
}
if (type == BRCMF_SDIO_FT_SUPER &&
(roundup(len, bus->blocksize) != rd->len)) {
brcmf_dbg(ERROR, "HW superframe header length error\n");
return false;
return -EPROTO;
}
if (type == BRCMF_SDIO_FT_SUB && len > rd->len) {
brcmf_dbg(ERROR, "HW subframe header length error\n");
return false;
return -EPROTO;
}
rd->len = len;
@ -1091,7 +1091,7 @@ static bool brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header,
SDPCM_GLOMDESC(&header[SDPCM_FRAMETAG_LEN])) {
brcmf_dbg(ERROR, "Glom descriptor found in superframe head\n");
rd->len = 0;
return false;
return -EINVAL;
}
rx_seq = SDPCM_PACKET_SEQUENCE(&header[SDPCM_FRAMETAG_LEN]);
rd->channel = SDPCM_PACKET_CHANNEL(&header[SDPCM_FRAMETAG_LEN]);
@ -1102,18 +1102,18 @@ static bool brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header,
bus->sdcnt.rx_toolong++;
brcmf_sdbrcm_rxfail(bus, false, false);
rd->len = 0;
return false;
return -EPROTO;
}
if (type == BRCMF_SDIO_FT_SUPER && rd->channel != SDPCM_GLOM_CHANNEL) {
brcmf_dbg(ERROR, "Wrong channel for superframe\n");
rd->len = 0;
return false;
return -EINVAL;
}
if (type == BRCMF_SDIO_FT_SUB && rd->channel != SDPCM_DATA_CHANNEL &&
rd->channel != SDPCM_EVENT_CHANNEL) {
brcmf_dbg(ERROR, "Wrong channel for subframe\n");
rd->len = 0;
return false;
return -EINVAL;
}
rd->dat_offset = SDPCM_DOFFSET_VALUE(&header[SDPCM_FRAMETAG_LEN]);
if (rd->dat_offset < SDPCM_HDRLEN || rd->dat_offset > rd->len) {
@ -1121,7 +1121,7 @@ static bool brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header,
bus->sdcnt.rx_badhdr++;
brcmf_sdbrcm_rxfail(bus, false, false);
rd->len = 0;
return false;
return -ENXIO;
}
if (rd->seq_num != rx_seq) {
brcmf_dbg(ERROR, "seq %d: sequence number error, expect %d\n",
@ -1131,7 +1131,7 @@ static bool brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header,
}
/* no need to check the reset for subframe */
if (type == BRCMF_SDIO_FT_SUB)
return true;
return 0;
rd->len_nxtfrm = header[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
if (rd->len_nxtfrm << 4 > MAX_RX_DATASZ) {
/* only warm for NON glom packet */
@ -1155,7 +1155,7 @@ static bool brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header,
}
bus->tx_max = tx_seq_max;
return true;
return 0;
}
static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
@ -1272,6 +1272,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
* read directly into the chained packet, or allocate a large
* packet and and copy into the chain.
*/
sdio_claim_host(bus->sdiodev->func[1]);
if (usechain) {
errcode = brcmf_sdcard_recv_chain(bus->sdiodev,
bus->sdiodev->sbwad,
@ -1293,6 +1294,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
dlen);
errcode = -1;
}
sdio_release_host(bus->sdiodev->func[1]);
bus->sdcnt.f2rxdata++;
/* On failure, kill the superframe, allow a couple retries */
@ -1301,6 +1303,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
dlen, errcode);
bus->sdiodev->bus_if->dstats.rx_errors++;
sdio_claim_host(bus->sdiodev->func[1]);
if (bus->glomerr++ < 3) {
brcmf_sdbrcm_rxfail(bus, true, true);
} else {
@ -1309,6 +1312,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
bus->sdcnt.rxglomfail++;
brcmf_sdbrcm_free_glom(bus);
}
sdio_release_host(bus->sdiodev->func[1]);
return 0;
}
@ -1318,8 +1322,10 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
rd_new.seq_num = rxseq;
rd_new.len = dlen;
errcode = -!brcmf_sdio_hdparser(bus, pfirst->data, &rd_new,
BRCMF_SDIO_FT_SUPER);
sdio_claim_host(bus->sdiodev->func[1]);
errcode = brcmf_sdio_hdparser(bus, pfirst->data, &rd_new,
BRCMF_SDIO_FT_SUPER);
sdio_release_host(bus->sdiodev->func[1]);
bus->cur_read.len = rd_new.len_nxtfrm << 4;
/* Remove superframe header, remember offset */
@ -1335,9 +1341,10 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
rd_new.len = pnext->len;
rd_new.seq_num = rxseq++;
errcode = -!brcmf_sdio_hdparser(bus, pnext->data,
&rd_new,
BRCMF_SDIO_FT_SUB);
sdio_claim_host(bus->sdiodev->func[1]);
errcode = brcmf_sdio_hdparser(bus, pnext->data, &rd_new,
BRCMF_SDIO_FT_SUB);
sdio_release_host(bus->sdiodev->func[1]);
brcmf_dbg_hex_dump(BRCMF_GLOM_ON(),
pnext->data, 32, "subframe:\n");
@ -1347,6 +1354,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
if (errcode) {
/* Terminate frame on error, request
a couple retries */
sdio_claim_host(bus->sdiodev->func[1]);
if (bus->glomerr++ < 3) {
/* Restore superframe header space */
skb_push(pfirst, sfdoff);
@ -1357,6 +1365,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
bus->sdcnt.rxglomfail++;
brcmf_sdbrcm_free_glom(bus);
}
sdio_release_host(bus->sdiodev->func[1]);
bus->cur_read.len = 0;
return 0;
}
@ -1397,11 +1406,8 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
pfirst->prev);
}
/* sent any remaining packets up */
if (bus->glom.qlen) {
up(&bus->sdsem);
if (bus->glom.qlen)
brcmf_rx_frame(bus->sdiodev->dev, ifidx, &bus->glom);
down(&bus->sdsem);
}
bus->sdcnt.rxglomframes++;
bus->sdcnt.rxglompkts += bus->glom.qlen;
@ -1442,21 +1448,24 @@ static void
brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff)
{
uint rdlen, pad;
u8 *buf = NULL, *rbuf;
int sdret;
brcmf_dbg(TRACE, "Enter\n");
/* Set rxctl for frame (w/optional alignment) */
bus->rxctl = bus->rxbuf;
bus->rxctl += BRCMF_FIRSTREAD;
pad = ((unsigned long)bus->rxctl % BRCMF_SDALIGN);
if (bus->rxblen)
buf = vzalloc(bus->rxblen);
if (!buf) {
brcmf_dbg(ERROR, "no memory for control frame\n");
goto done;
}
rbuf = bus->rxbuf;
pad = ((unsigned long)rbuf % BRCMF_SDALIGN);
if (pad)
bus->rxctl += (BRCMF_SDALIGN - pad);
bus->rxctl -= BRCMF_FIRSTREAD;
rbuf += (BRCMF_SDALIGN - pad);
/* Copy the already-read portion over */
memcpy(bus->rxctl, hdr, BRCMF_FIRSTREAD);
memcpy(buf, hdr, BRCMF_FIRSTREAD);
if (len <= BRCMF_FIRSTREAD)
goto gotpkt;
@ -1493,11 +1502,11 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff)
goto done;
}
/* Read remainder of frame body into the rxctl buffer */
/* Read remain of frame body */
sdret = brcmf_sdcard_recv_buf(bus->sdiodev,
bus->sdiodev->sbwad,
SDIO_FUNC_2,
F2SYNC, (bus->rxctl + BRCMF_FIRSTREAD), rdlen);
F2SYNC, rbuf, rdlen);
bus->sdcnt.f2rxdata++;
/* Control frame failures need retransmission */
@ -1507,16 +1516,26 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff)
bus->sdcnt.rxc_errors++;
brcmf_sdbrcm_rxfail(bus, true, true);
goto done;
}
} else
memcpy(buf + BRCMF_FIRSTREAD, rbuf, rdlen);
gotpkt:
brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && BRCMF_CTL_ON(),
bus->rxctl, len, "RxCtrl:\n");
buf, len, "RxCtrl:\n");
/* Point to valid data and indicate its length */
bus->rxctl += doff;
spin_lock_bh(&bus->rxctl_lock);
if (bus->rxctl) {
brcmf_dbg(ERROR, "last control frame is being processed.\n");
spin_unlock_bh(&bus->rxctl_lock);
vfree(buf);
goto done;
}
bus->rxctl = buf + doff;
bus->rxctl_orig = buf;
bus->rxlen = len - doff;
spin_unlock_bh(&bus->rxctl_lock);
done:
/* Awake any waiters */
@ -1571,6 +1590,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
rd->len_left = rd->len;
/* read header first for unknow frame length */
sdio_claim_host(bus->sdiodev->func[1]);
if (!rd->len) {
sdret = brcmf_sdcard_recv_buf(bus->sdiodev,
bus->sdiodev->sbwad,
@ -1583,6 +1603,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
sdret);
bus->sdcnt.rx_hdrfail++;
brcmf_sdbrcm_rxfail(bus, true, true);
sdio_release_host(bus->sdiodev->func[1]);
continue;
}
@ -1590,8 +1611,9 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
bus->rxhdr, SDPCM_HDRLEN,
"RxHdr:\n");
if (!brcmf_sdio_hdparser(bus, bus->rxhdr, rd,
BRCMF_SDIO_FT_NORMAL)) {
if (brcmf_sdio_hdparser(bus, bus->rxhdr, rd,
BRCMF_SDIO_FT_NORMAL)) {
sdio_release_host(bus->sdiodev->func[1]);
if (!bus->rxpending)
break;
else
@ -1607,6 +1629,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
rd->len_nxtfrm = 0;
/* treat all packet as event if we don't know */
rd->channel = SDPCM_EVENT_CHANNEL;
sdio_release_host(bus->sdiodev->func[1]);
continue;
}
rd->len_left = rd->len > BRCMF_FIRSTREAD ?
@ -1624,6 +1647,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
bus->sdiodev->bus_if->dstats.rx_dropped++;
brcmf_sdbrcm_rxfail(bus, false,
RETRYCHAN(rd->channel));
sdio_release_host(bus->sdiodev->func[1]);
continue;
}
skb_pull(pkt, head_read);
@ -1632,14 +1656,17 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
sdret = brcmf_sdcard_recv_pkt(bus->sdiodev, bus->sdiodev->sbwad,
SDIO_FUNC_2, F2SYNC, pkt);
bus->sdcnt.f2rxdata++;
sdio_release_host(bus->sdiodev->func[1]);
if (sdret < 0) {
brcmf_dbg(ERROR, "read %d bytes from channel %d failed: %d\n",
rd->len, rd->channel, sdret);
brcmu_pkt_buf_free_skb(pkt);
bus->sdiodev->bus_if->dstats.rx_errors++;
sdio_claim_host(bus->sdiodev->func[1]);
brcmf_sdbrcm_rxfail(bus, true,
RETRYCHAN(rd->channel));
sdio_release_host(bus->sdiodev->func[1]);
continue;
}
@ -1650,8 +1677,9 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
} else {
memcpy(bus->rxhdr, pkt->data, SDPCM_HDRLEN);
rd_new.seq_num = rd->seq_num;
if (!brcmf_sdio_hdparser(bus, bus->rxhdr, &rd_new,
BRCMF_SDIO_FT_NORMAL)) {
sdio_claim_host(bus->sdiodev->func[1]);
if (brcmf_sdio_hdparser(bus, bus->rxhdr, &rd_new,
BRCMF_SDIO_FT_NORMAL)) {
rd->len = 0;
brcmu_pkt_buf_free_skb(pkt);
}
@ -1662,9 +1690,11 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
roundup(rd_new.len, 16) >> 4);
rd->len = 0;
brcmf_sdbrcm_rxfail(bus, true, true);
sdio_release_host(bus->sdiodev->func[1]);
brcmu_pkt_buf_free_skb(pkt);
continue;
}
sdio_release_host(bus->sdiodev->func[1]);
rd->len_nxtfrm = rd_new.len_nxtfrm;
rd->channel = rd_new.channel;
rd->dat_offset = rd_new.dat_offset;
@ -1680,7 +1710,9 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
rd_new.seq_num);
/* Force retry w/normal header read */
rd->len = 0;
sdio_claim_host(bus->sdiodev->func[1]);
brcmf_sdbrcm_rxfail(bus, false, true);
sdio_release_host(bus->sdiodev->func[1]);
brcmu_pkt_buf_free_skb(pkt);
continue;
}
@ -1703,7 +1735,9 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
} else {
brcmf_dbg(ERROR, "%s: glom superframe w/o "
"descriptor!\n", __func__);
sdio_claim_host(bus->sdiodev->func[1]);
brcmf_sdbrcm_rxfail(bus, false, false);
sdio_release_host(bus->sdiodev->func[1]);
}
/* prepare the descriptor for the next read */
rd->len = rd->len_nxtfrm << 4;
@ -1734,10 +1768,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
continue;
}
/* Unlock during rx call */
up(&bus->sdsem);
brcmf_rx_packet(bus->sdiodev->dev, ifidx, pkt);
down(&bus->sdsem);
}
rxcount = maxframes - rxleft;
@ -1754,15 +1785,6 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
return rxcount;
}
static void
brcmf_sdbrcm_wait_for_event(struct brcmf_sdio *bus, bool *lockvar)
{
up(&bus->sdsem);
wait_event_interruptible_timeout(bus->ctrl_wait, !*lockvar, HZ * 2);
down(&bus->sdsem);
return;
}
static void
brcmf_sdbrcm_wait_event_wakeup(struct brcmf_sdio *bus)
{
@ -1864,6 +1886,7 @@ static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt,
if (len & (ALIGNMENT - 1))
len = roundup(len, ALIGNMENT);
sdio_claim_host(bus->sdiodev->func[1]);
ret = brcmf_sdcard_send_pkt(bus->sdiodev, bus->sdiodev->sbwad,
SDIO_FUNC_2, F2SYNC, pkt);
bus->sdcnt.f2txdata++;
@ -1891,15 +1914,14 @@ static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt,
}
}
sdio_release_host(bus->sdiodev->func[1]);
if (ret == 0)
bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
done:
/* restore pkt buffer pointer before calling tx complete routine */
skb_pull(pkt, SDPCM_HDRLEN + pad);
up(&bus->sdsem);
brcmf_txcomplete(bus->sdiodev->dev, pkt, ret != 0);
down(&bus->sdsem);
if (free_pkt)
brcmu_pkt_buf_free_skb(pkt);
@ -1940,9 +1962,11 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes)
/* In poll mode, need to check for other events */
if (!bus->intr && cnt) {
/* Check device status, signal pending interrupt */
sdio_claim_host(bus->sdiodev->func[1]);
ret = r_sdreg32(bus, &intstatus,
offsetof(struct sdpcmd_regs,
intstatus));
sdio_release_host(bus->sdiodev->func[1]);
bus->sdcnt.f2txdata++;
if (ret != 0)
break;
@ -1979,7 +2003,7 @@ static void brcmf_sdbrcm_bus_stop(struct device *dev)
bus->watchdog_tsk = NULL;
}
down(&bus->sdsem);
sdio_claim_host(bus->sdiodev->func[1]);
/* Enable clock for device interrupts */
brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
@ -2013,6 +2037,7 @@ static void brcmf_sdbrcm_bus_stop(struct device *dev)
/* Turn off the backplane clock (only) */
brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false);
sdio_release_host(bus->sdiodev->func[1]);
/* Clear the data packet queues */
brcmu_pktq_flush(&bus->txq, true, NULL, NULL);
@ -2023,14 +2048,14 @@ static void brcmf_sdbrcm_bus_stop(struct device *dev)
brcmf_sdbrcm_free_glom(bus);
/* Clear rx control and wake any waiters */
spin_lock_bh(&bus->rxctl_lock);
bus->rxlen = 0;
spin_unlock_bh(&bus->rxctl_lock);
brcmf_sdbrcm_dcmd_resp_wake(bus);
/* Reset some F2 state stuff */
bus->rxskip = false;
bus->tx_seq = bus->rx_seq = 0;
up(&bus->sdsem);
}
#ifdef CONFIG_BRCMFMAC_SDIO_OOB
@ -2114,7 +2139,7 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
brcmf_dbg(TRACE, "Enter\n");
down(&bus->sdsem);
sdio_claim_host(bus->sdiodev->func[1]);
/* If waiting for HTAVAIL, check status */
if (bus->clkstate == CLK_PENDING) {
@ -2168,9 +2193,7 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
/* Pending interrupt indicates new device status */
if (atomic_read(&bus->ipend) > 0) {
atomic_set(&bus->ipend, 0);
sdio_claim_host(bus->sdiodev->func[1]);
err = brcmf_sdio_intr_rstatus(bus);
sdio_release_host(bus->sdiodev->func[1]);
}
/* Start with leftover status bits */
@ -2199,6 +2222,8 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
intstatus |= brcmf_sdbrcm_hostmail(bus);
}
sdio_release_host(bus->sdiodev->func[1]);
/* Generally don't ask for these, can get CRC errors... */
if (intstatus & I_WR_OOSYNC) {
brcmf_dbg(ERROR, "Dongle reports WR_OOSYNC\n");
@ -2245,6 +2270,7 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
(bus->clkstate == CLK_AVAIL)) {
int i;
sdio_claim_host(bus->sdiodev->func[1]);
err = brcmf_sdcard_send_buf(bus->sdiodev, bus->sdiodev->sbwad,
SDIO_FUNC_2, F2SYNC, bus->ctrl_frame_buf,
(u32) bus->ctrl_frame_len);
@ -2278,6 +2304,7 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
} else {
bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
}
sdio_release_host(bus->sdiodev->func[1]);
bus->ctrl_frame_stat = false;
brcmf_sdbrcm_wait_event_wakeup(bus);
}
@ -2307,10 +2334,10 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
if ((bus->clkstate != CLK_PENDING)
&& bus->idletime == BRCMF_IDLE_IMMEDIATE) {
bus->activity = false;
sdio_claim_host(bus->sdiodev->func[1]);
brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
sdio_release_host(bus->sdiodev->func[1]);
}
up(&bus->sdsem);
}
static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt)
@ -2601,11 +2628,10 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
/* precondition: IS_ALIGNED((unsigned long)frame, 2) */
/* Need to lock here to protect txseq and SDIO tx calls */
down(&bus->sdsem);
/* Make sure backplane clock is on */
sdio_claim_host(bus->sdiodev->func[1]);
brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
sdio_release_host(bus->sdiodev->func[1]);
/* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
*(__le16 *) frame = cpu_to_le16((u16) msglen);
@ -2628,7 +2654,9 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
bus->ctrl_frame_buf = frame;
bus->ctrl_frame_len = len;
brcmf_sdbrcm_wait_for_event(bus, &bus->ctrl_frame_stat);
wait_event_interruptible_timeout(bus->ctrl_wait,
!bus->ctrl_frame_stat,
msecs_to_jiffies(2000));
if (!bus->ctrl_frame_stat) {
brcmf_dbg(INFO, "ctrl_frame_stat == false\n");
@ -2647,7 +2675,9 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
frame, min_t(u16, len, 16), "TxHdr:\n");
do {
sdio_claim_host(bus->sdiodev->func[1]);
ret = brcmf_tx_frame(bus, frame, len);
sdio_release_host(bus->sdiodev->func[1]);
} while (ret < 0 && retries++ < TXRETRIES);
}
@ -2657,13 +2687,13 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
spin_unlock_irqrestore(&bus->dpc_tl_lock, flags);
bus->activity = false;
sdio_claim_host(bus->sdiodev->func[1]);
brcmf_sdbrcm_clkctl(bus, CLK_NONE, true);
sdio_release_host(bus->sdiodev->func[1]);
} else {
spin_unlock_irqrestore(&bus->dpc_tl_lock, flags);
}
up(&bus->sdsem);
if (ret)
bus->sdcnt.tx_ctlerrs++;
else
@ -2693,8 +2723,10 @@ static int brcmf_sdio_readshared(struct brcmf_sdio *bus,
* Read last word in socram to determine
* address of sdpcm_shared structure
*/
sdio_claim_host(bus->sdiodev->func[1]);
rv = brcmf_sdbrcm_membytes(bus, false, shaddr,
(u8 *)&addr_le, 4);
sdio_claim_host(bus->sdiodev->func[1]);
if (rv < 0)
return rv;
@ -2713,8 +2745,10 @@ static int brcmf_sdio_readshared(struct brcmf_sdio *bus,
}
/* Read hndrte_shared structure */
sdio_claim_host(bus->sdiodev->func[1]);
rv = brcmf_sdbrcm_membytes(bus, false, addr, (u8 *)&sh_le,
sizeof(struct sdpcm_shared_le));
sdio_release_host(bus->sdiodev->func[1]);
if (rv < 0)
return rv;
@ -2817,12 +2851,14 @@ static int brcmf_sdio_trap_info(struct brcmf_sdio *bus, struct sdpcm_shared *sh,
if ((sh->flags & SDPCM_SHARED_TRAP) == 0)
return 0;
sdio_claim_host(bus->sdiodev->func[1]);
error = brcmf_sdbrcm_membytes(bus, false, sh->trap_addr, (u8 *)&tr,
sizeof(struct brcmf_trap_info));
if (error < 0)
return error;
nbytes = brcmf_sdio_dump_console(bus, sh, data, count);
sdio_release_host(bus->sdiodev->func[1]);
if (nbytes < 0)
return nbytes;
@ -2868,6 +2904,7 @@ static int brcmf_sdio_assert_info(struct brcmf_sdio *bus,
return 0;
}
sdio_claim_host(bus->sdiodev->func[1]);
if (sh->assert_file_addr != 0) {
error = brcmf_sdbrcm_membytes(bus, false, sh->assert_file_addr,
(u8 *)file, 80);
@ -2880,6 +2917,7 @@ static int brcmf_sdio_assert_info(struct brcmf_sdio *bus,
if (error < 0)
return error;
}
sdio_release_host(bus->sdiodev->func[1]);
res = scnprintf(buf, sizeof(buf),
"dongle assert: %s:%d: assert(%s)\n",
@ -2892,9 +2930,7 @@ static int brcmf_sdbrcm_checkdied(struct brcmf_sdio *bus)
int error;
struct sdpcm_shared sh;
down(&bus->sdsem);
error = brcmf_sdio_readshared(bus, &sh);
up(&bus->sdsem);
if (error < 0)
return error;
@ -2921,7 +2957,6 @@ static int brcmf_sdbrcm_died_dump(struct brcmf_sdio *bus, char __user *data,
if (pos != 0)
return 0;
down(&bus->sdsem);
error = brcmf_sdio_readshared(bus, &sh);
if (error < 0)
goto done;
@ -2938,7 +2973,6 @@ static int brcmf_sdbrcm_died_dump(struct brcmf_sdio *bus, char __user *data,
error += nbytes;
*ppos += error;
done:
up(&bus->sdsem);
return error;
}
@ -2989,6 +3023,7 @@ brcmf_sdbrcm_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen)
int timeleft;
uint rxlen = 0;
bool pending;
u8 *buf;
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
struct brcmf_sdio *bus = sdiodev->bus;
@ -2998,11 +3033,15 @@ brcmf_sdbrcm_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen)
/* Wait until control frame is available */
timeleft = brcmf_sdbrcm_dcmd_resp_wait(bus, &bus->rxlen, &pending);
down(&bus->sdsem);
spin_lock_bh(&bus->rxctl_lock);
rxlen = bus->rxlen;
memcpy(msg, bus->rxctl, min(msglen, rxlen));
bus->rxctl = NULL;
buf = bus->rxctl_orig;
bus->rxctl_orig = NULL;
bus->rxlen = 0;
up(&bus->sdsem);
spin_unlock_bh(&bus->rxctl_lock);
vfree(buf);
if (rxlen) {
brcmf_dbg(CTL, "resumed on rxctl frame, got %d expected %d\n",
@ -3338,13 +3377,16 @@ brcmf_sdbrcm_download_firmware(struct brcmf_sdio *bus)
{
bool ret;
/* Download the firmware */
sdio_claim_host(bus->sdiodev->func[1]);
brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
ret = _brcmf_sdbrcm_download_firmware(bus) == 0;
brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false);
sdio_release_host(bus->sdiodev->func[1]);
return ret;
}
@ -3373,7 +3415,7 @@ static int brcmf_sdbrcm_bus_init(struct device *dev)
bus->sdcnt.tickcnt = 0;
brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS);
down(&bus->sdsem);
sdio_claim_host(bus->sdiodev->func[1]);
/* Make sure backplane clock is on, needed to generate F2 interrupt */
brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
@ -3442,7 +3484,7 @@ static int brcmf_sdbrcm_bus_init(struct device *dev)
brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
exit:
up(&bus->sdsem);
sdio_release_host(bus->sdiodev->func[1]);
return ret;
}
@ -3489,8 +3531,6 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)
brcmf_dbg(TIMER, "Enter\n");
down(&bus->sdsem);
/* Poll period: check device if appropriate. */
if (bus->poll && (++bus->polltick >= bus->pollrate)) {
u32 intstatus = 0;
@ -3507,9 +3547,11 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)
u8 devpend;
spin_unlock_irqrestore(&bus->dpc_tl_lock,
flags);
sdio_claim_host(bus->sdiodev->func[1]);
devpend = brcmf_sdio_regrb(bus->sdiodev,
SDIO_CCCR_INTx,
NULL);
sdio_release_host(bus->sdiodev->func[1]);
intstatus =
devpend & (INTR_STATUS_FUNC1 |
INTR_STATUS_FUNC2);
@ -3534,16 +3576,18 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)
}
#ifdef DEBUG
/* Poll for console output periodically */
if (bus_if->state == BRCMF_BUS_DATA &&
if (bus_if && bus_if->state == BRCMF_BUS_DATA &&
bus->console_interval != 0) {
bus->console.count += BRCMF_WD_POLL_MS;
if (bus->console.count >= bus->console_interval) {
bus->console.count -= bus->console_interval;
sdio_claim_host(bus->sdiodev->func[1]);
/* Make sure backplane clock is on */
brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
if (brcmf_sdbrcm_readconsole(bus) < 0)
/* stop on error */
bus->console_interval = 0;
sdio_release_host(bus->sdiodev->func[1]);
}
}
#endif /* DEBUG */
@ -3556,13 +3600,13 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)
bus->activity = false;
brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS);
} else {
sdio_claim_host(bus->sdiodev->func[1]);
brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
sdio_release_host(bus->sdiodev->func[1]);
}
}
}
up(&bus->sdsem);
return (atomic_read(&bus->ipend) > 0);
}
@ -3657,6 +3701,8 @@ brcmf_sdbrcm_probe_attach(struct brcmf_sdio *bus, u32 regsva)
bus->alp_only = true;
sdio_claim_host(bus->sdiodev->func[1]);
pr_debug("F1 signature read @0x18000000=0x%4x\n",
brcmf_sdio_regrl(bus->sdiodev, SI_ENUM_BASE, NULL));
@ -3704,6 +3750,8 @@ brcmf_sdbrcm_probe_attach(struct brcmf_sdio *bus, u32 regsva)
reg_val = brcmf_sdio_regrl(bus->sdiodev, reg_addr, NULL);
brcmf_sdio_regwl(bus->sdiodev, reg_addr, reg_val | CC_BPRESEN, NULL);
sdio_release_host(bus->sdiodev->func[1]);
brcmu_pktq_init(&bus->txq, (PRIOMASK + 1), TXQLEN);
/* Locate an appropriately-aligned portion of hdrbuf */
@ -3719,6 +3767,7 @@ brcmf_sdbrcm_probe_attach(struct brcmf_sdio *bus, u32 regsva)
return true;
fail:
sdio_release_host(bus->sdiodev->func[1]);
return false;
}
@ -3726,6 +3775,8 @@ static bool brcmf_sdbrcm_probe_init(struct brcmf_sdio *bus)
{
brcmf_dbg(TRACE, "Enter\n");
sdio_claim_host(bus->sdiodev->func[1]);
/* Disable F2 to clear any intermediate frame state on the dongle */
brcmf_sdio_regwb(bus->sdiodev, SDIO_CCCR_IOEx,
SDIO_FUNC_ENABLE_1, NULL);
@ -3736,6 +3787,8 @@ static bool brcmf_sdbrcm_probe_init(struct brcmf_sdio *bus)
/* Done with backplane-dependent accesses, can drop clock... */
brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
sdio_release_host(bus->sdiodev->func[1]);
/* ...and initialize clock/power states */
bus->clkstate = CLK_SDONLY;
bus->idletime = BRCMF_IDLE_INTERVAL;
@ -3791,8 +3844,10 @@ static void brcmf_sdbrcm_release_dongle(struct brcmf_sdio *bus)
brcmf_dbg(TRACE, "Enter\n");
if (bus->ci) {
sdio_claim_host(bus->sdiodev->func[1]);
brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
sdio_release_host(bus->sdiodev->func[1]);
brcmf_sdio_chip_detach(&bus->ci);
if (bus->vars && bus->varsz)
kfree(bus->vars);
@ -3812,7 +3867,8 @@ static void brcmf_sdbrcm_release(struct brcmf_sdio *bus)
brcmf_sdio_intr_unregister(bus->sdiodev);
cancel_work_sync(&bus->datawork);
destroy_workqueue(bus->brcmf_wq);
if (bus->brcmf_wq)
destroy_workqueue(bus->brcmf_wq);
if (bus->sdiodev->bus_if->drvr) {
brcmf_detach(bus->sdiodev->dev);
@ -3854,31 +3910,29 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev)
bus->txminmax = BRCMF_TXMINMAX;
bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1;
INIT_WORK(&bus->datawork, brcmf_sdio_dataworker);
bus->brcmf_wq = create_singlethread_workqueue("brcmf_wq");
if (bus->brcmf_wq == NULL) {
brcmf_dbg(ERROR, "insufficient memory to create txworkqueue\n");
goto fail;
}
/* attempt to attach to the dongle */
if (!(brcmf_sdbrcm_probe_attach(bus, regsva))) {
brcmf_dbg(ERROR, "brcmf_sdbrcm_probe_attach failed\n");
goto fail;
}
spin_lock_init(&bus->rxctl_lock);
spin_lock_init(&bus->txqlock);
init_waitqueue_head(&bus->ctrl_wait);
init_waitqueue_head(&bus->dcmd_resp_wait);
bus->brcmf_wq = create_singlethread_workqueue("brcmf_wq");
if (bus->brcmf_wq == NULL) {
brcmf_dbg(ERROR, "insufficient memory to create txworkqueue\n");
goto fail;
}
INIT_WORK(&bus->datawork, brcmf_sdio_dataworker);
/* Set up the watchdog timer */
init_timer(&bus->timer);
bus->timer.data = (unsigned long)bus;
bus->timer.function = brcmf_sdbrcm_watchdog;
/* Initialize thread based operation and lock */
sema_init(&bus->sdsem, 1);
/* Initialize watchdog thread */
init_completion(&bus->watchdog_wait);
bus->watchdog_tsk = kthread_run(brcmf_sdbrcm_watchdog_thread,
@ -3941,10 +3995,8 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev)
/* if firmware path present try to download and bring up bus */
ret = brcmf_bus_start(bus->sdiodev->dev);
if (ret != 0) {
if (ret == -ENOLINK) {
brcmf_dbg(ERROR, "dongle is not responding\n");
goto fail;
}
brcmf_dbg(ERROR, "dongle is not responding\n");
goto fail;
}
return bus;

View File

@ -0,0 +1,509 @@
/*
* Copyright (c) 2012 Broadcom Corporation
*
* 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.
*/
#include <linux/netdevice.h>
#include "brcmu_wifi.h"
#include "brcmu_utils.h"
#include "dhd.h"
#include "dhd_dbg.h"
#include "fweh.h"
#include "fwil.h"
/**
* struct brcm_ethhdr - broadcom specific ether header.
*
* @subtype: subtype for this packet.
* @length: TODO: length of appended data.
* @version: version indication.
* @oui: OUI of this packet.
* @usr_subtype: subtype for this OUI.
*/
struct brcm_ethhdr {
__be16 subtype;
__be16 length;
u8 version;
u8 oui[3];
__be16 usr_subtype;
} __packed;
struct brcmf_event_msg_be {
__be16 version;
__be16 flags;
__be32 event_type;
__be32 status;
__be32 reason;
__be32 auth_type;
__be32 datalen;
u8 addr[ETH_ALEN];
char ifname[IFNAMSIZ];
u8 ifidx;
u8 bsscfgidx;
} __packed;
/**
* struct brcmf_event - contents of broadcom event packet.
*
* @eth: standard ether header.
* @hdr: broadcom specific ether header.
* @msg: common part of the actual event message.
*/
struct brcmf_event {
struct ethhdr eth;
struct brcm_ethhdr hdr;
struct brcmf_event_msg_be msg;
} __packed;
/**
* struct brcmf_fweh_queue_item - event item on event queue.
*
* @q: list element for queuing.
* @code: event code.
* @ifidx: interface index related to this event.
* @ifaddr: ethernet address for interface.
* @emsg: common parameters of the firmware event message.
* @data: event specific data part of the firmware event.
*/
struct brcmf_fweh_queue_item {
struct list_head q;
enum brcmf_fweh_event_code code;
u8 ifidx;
u8 ifaddr[ETH_ALEN];
struct brcmf_event_msg_be emsg;
u8 data[0];
};
/**
* struct brcmf_fweh_event_name - code, name mapping entry.
*/
struct brcmf_fweh_event_name {
enum brcmf_fweh_event_code code;
const char *name;
};
#ifdef DEBUG
/* array for mapping code to event name */
static struct brcmf_fweh_event_name fweh_event_names[] = {
{ BRCMF_E_SET_SSID, "SET_SSID" },
{ BRCMF_E_JOIN, "JOIN" },
{ BRCMF_E_START, "START" },
{ BRCMF_E_AUTH, "AUTH" },
{ BRCMF_E_AUTH_IND, "AUTH_IND" },
{ BRCMF_E_DEAUTH, "DEAUTH" },
{ BRCMF_E_DEAUTH_IND, "DEAUTH_IND" },
{ BRCMF_E_ASSOC, "ASSOC" },
{ BRCMF_E_ASSOC_IND, "ASSOC_IND" },
{ BRCMF_E_REASSOC, "REASSOC" },
{ BRCMF_E_REASSOC_IND, "REASSOC_IND" },
{ BRCMF_E_DISASSOC, "DISASSOC" },
{ BRCMF_E_DISASSOC_IND, "DISASSOC_IND" },
{ BRCMF_E_QUIET_START, "START_QUIET" },
{ BRCMF_E_QUIET_END, "END_QUIET" },
{ BRCMF_E_BEACON_RX, "BEACON_RX" },
{ BRCMF_E_LINK, "LINK" },
{ BRCMF_E_MIC_ERROR, "MIC_ERROR" },
{ BRCMF_E_NDIS_LINK, "NDIS_LINK" },
{ BRCMF_E_ROAM, "ROAM" },
{ BRCMF_E_TXFAIL, "TXFAIL" },
{ BRCMF_E_PMKID_CACHE, "PMKID_CACHE" },
{ BRCMF_E_RETROGRADE_TSF, "RETROGRADE_TSF" },
{ BRCMF_E_PRUNE, "PRUNE" },
{ BRCMF_E_AUTOAUTH, "AUTOAUTH" },
{ BRCMF_E_EAPOL_MSG, "EAPOL_MSG" },
{ BRCMF_E_SCAN_COMPLETE, "SCAN_COMPLETE" },
{ BRCMF_E_ADDTS_IND, "ADDTS_IND" },
{ BRCMF_E_DELTS_IND, "DELTS_IND" },
{ BRCMF_E_BCNSENT_IND, "BCNSENT_IND" },
{ BRCMF_E_BCNRX_MSG, "BCNRX_MSG" },
{ BRCMF_E_BCNLOST_MSG, "BCNLOST_MSG" },
{ BRCMF_E_ROAM_PREP, "ROAM_PREP" },
{ BRCMF_E_PFN_NET_FOUND, "PNO_NET_FOUND" },
{ BRCMF_E_PFN_NET_LOST, "PNO_NET_LOST" },
{ BRCMF_E_RESET_COMPLETE, "RESET_COMPLETE" },
{ BRCMF_E_JOIN_START, "JOIN_START" },
{ BRCMF_E_ROAM_START, "ROAM_START" },
{ BRCMF_E_ASSOC_START, "ASSOC_START" },
{ BRCMF_E_IBSS_ASSOC, "IBSS_ASSOC" },
{ BRCMF_E_RADIO, "RADIO" },
{ BRCMF_E_PSM_WATCHDOG, "PSM_WATCHDOG" },
{ BRCMF_E_PROBREQ_MSG, "PROBREQ_MSG" },
{ BRCMF_E_SCAN_CONFIRM_IND, "SCAN_CONFIRM_IND" },
{ BRCMF_E_PSK_SUP, "PSK_SUP" },
{ BRCMF_E_COUNTRY_CODE_CHANGED, "COUNTRY_CODE_CHANGED" },
{ BRCMF_E_EXCEEDED_MEDIUM_TIME, "EXCEEDED_MEDIUM_TIME" },
{ BRCMF_E_ICV_ERROR, "ICV_ERROR" },
{ BRCMF_E_UNICAST_DECODE_ERROR, "UNICAST_DECODE_ERROR" },
{ BRCMF_E_MULTICAST_DECODE_ERROR, "MULTICAST_DECODE_ERROR" },
{ BRCMF_E_TRACE, "TRACE" },
{ BRCMF_E_IF, "IF" },
{ BRCMF_E_RSSI, "RSSI" },
{ BRCMF_E_PFN_SCAN_COMPLETE, "PFN_SCAN_COMPLETE" },
{ BRCMF_E_EXTLOG_MSG, "EXTLOG_MSG" },
{ BRCMF_E_ACTION_FRAME, "ACTION_FRAME" },
{ BRCMF_E_ACTION_FRAME_COMPLETE, "ACTION_FRAME_COMPLETE" },
{ BRCMF_E_PRE_ASSOC_IND, "PRE_ASSOC_IND" },
{ BRCMF_E_PRE_REASSOC_IND, "PRE_REASSOC_IND" },
{ BRCMF_E_CHANNEL_ADOPTED, "CHANNEL_ADOPTED" },
{ BRCMF_E_AP_STARTED, "AP_STARTED" },
{ BRCMF_E_DFS_AP_STOP, "DFS_AP_STOP" },
{ BRCMF_E_DFS_AP_RESUME, "DFS_AP_RESUME" },
{ BRCMF_E_ESCAN_RESULT, "ESCAN_RESULT" },
{ BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE, "ACTION_FRM_OFF_CHAN_CMPLT" },
{ BRCMF_E_DCS_REQUEST, "DCS_REQUEST" },
{ BRCMF_E_FIFO_CREDIT_MAP, "FIFO_CREDIT_MAP"}
};
/**
* brcmf_fweh_event_name() - returns name for given event code.
*
* @code: code to lookup.
*/
static const char *brcmf_fweh_event_name(enum brcmf_fweh_event_code code)
{
int i;
for (i = 0; i < ARRAY_SIZE(fweh_event_names); i++) {
if (fweh_event_names[i].code == code)
return fweh_event_names[i].name;
}
return "unknown";
}
#else
static const char *brcmf_fweh_event_name(enum brcmf_fweh_event_code code)
{
return "nodebug";
}
#endif
/**
* brcmf_fweh_queue_event() - create and queue event.
*
* @fweh: firmware event handling info.
* @event: event queue entry.
*/
static void brcmf_fweh_queue_event(struct brcmf_fweh_info *fweh,
struct brcmf_fweh_queue_item *event)
{
ulong flags;
spin_lock_irqsave(&fweh->evt_q_lock, flags);
list_add_tail(&event->q, &fweh->event_q);
spin_unlock_irqrestore(&fweh->evt_q_lock, flags);
schedule_work(&fweh->event_work);
}
static int brcmf_fweh_call_event_handler(struct brcmf_if *ifp,
enum brcmf_fweh_event_code code,
struct brcmf_event_msg *emsg,
void *data)
{
struct brcmf_fweh_info *fweh;
int err = -EINVAL;
if (ifp) {
fweh = &ifp->drvr->fweh;
/* handle the event if valid interface and handler */
if (ifp->ndev && fweh->evt_handler[code])
err = fweh->evt_handler[code](ifp, emsg, data);
else
brcmf_dbg(ERROR, "unhandled event %d ignored\n", code);
} else {
brcmf_dbg(ERROR, "no interface object\n");
}
return err;
}
/**
* brcmf_fweh_handle_if_event() - handle IF event.
*
* @drvr: driver information object.
* @item: queue entry.
* @ifpp: interface object (may change upon ADD action).
*/
static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr,
struct brcmf_event_msg *emsg,
void *data)
{
struct brcmf_if_event *ifevent = data;
struct brcmf_if *ifp;
int err = 0;
brcmf_dbg(EVENT, "action: %u idx: %u bsscfg: %u flags: %u\n",
ifevent->action, ifevent->ifidx,
ifevent->bssidx, ifevent->flags);
if (ifevent->ifidx >= BRCMF_MAX_IFS) {
brcmf_dbg(ERROR, "invalid interface index: %u\n",
ifevent->ifidx);
return;
}
ifp = drvr->iflist[ifevent->ifidx];
if (ifevent->action == BRCMF_E_IF_ADD) {
brcmf_dbg(EVENT, "adding %s (%pM)\n", emsg->ifname,
emsg->addr);
ifp = brcmf_add_if(drvr, ifevent->ifidx, ifevent->bssidx,
emsg->ifname, emsg->addr);
if (IS_ERR(ifp))
return;
if (!drvr->fweh.evt_handler[BRCMF_E_IF])
err = brcmf_net_attach(ifp);
}
err = brcmf_fweh_call_event_handler(ifp, emsg->event_code, emsg, data);
if (ifevent->action == BRCMF_E_IF_DEL)
brcmf_del_if(drvr, ifevent->ifidx);
}
/**
* brcmf_fweh_dequeue_event() - get event from the queue.
*
* @fweh: firmware event handling info.
*/
static struct brcmf_fweh_queue_item *
brcmf_fweh_dequeue_event(struct brcmf_fweh_info *fweh)
{
struct brcmf_fweh_queue_item *event = NULL;
ulong flags;
spin_lock_irqsave(&fweh->evt_q_lock, flags);
if (!list_empty(&fweh->event_q)) {
event = list_first_entry(&fweh->event_q,
struct brcmf_fweh_queue_item, q);
list_del(&event->q);
}
spin_unlock_irqrestore(&fweh->evt_q_lock, flags);
return event;
}
/**
* brcmf_fweh_event_worker() - firmware event worker.
*
* @work: worker object.
*/
static void brcmf_fweh_event_worker(struct work_struct *work)
{
struct brcmf_pub *drvr;
struct brcmf_if *ifp;
struct brcmf_fweh_info *fweh;
struct brcmf_fweh_queue_item *event;
int err = 0;
struct brcmf_event_msg_be *emsg_be;
struct brcmf_event_msg emsg;
fweh = container_of(work, struct brcmf_fweh_info, event_work);
drvr = container_of(fweh, struct brcmf_pub, fweh);
while ((event = brcmf_fweh_dequeue_event(fweh))) {
ifp = drvr->iflist[event->ifidx];
brcmf_dbg(EVENT, "event %s (%u) ifidx %u bsscfg %u addr %pM:\n",
brcmf_fweh_event_name(event->code), event->code,
event->emsg.ifidx, event->emsg.bsscfgidx,
event->emsg.addr);
/* convert event message */
emsg_be = &event->emsg;
emsg.version = be16_to_cpu(emsg_be->version);
emsg.flags = be16_to_cpu(emsg_be->flags);
emsg.event_code = event->code;
emsg.status = be32_to_cpu(emsg_be->status);
emsg.reason = be32_to_cpu(emsg_be->reason);
emsg.auth_type = be32_to_cpu(emsg_be->auth_type);
emsg.datalen = be32_to_cpu(emsg_be->datalen);
memcpy(emsg.addr, emsg_be->addr, ETH_ALEN);
memcpy(emsg.ifname, emsg_be->ifname, sizeof(emsg.ifname));
emsg.ifidx = emsg_be->ifidx;
emsg.bsscfgidx = emsg_be->bsscfgidx;
brcmf_dbg(EVENT, " version %u flags %u status %u reason %u\n",
emsg.version, emsg.flags, emsg.status, emsg.reason);
brcmf_dbg_hex_dump(BRCMF_EVENT_ON(), event->data,
min_t(u32, emsg.datalen, 64),
"appended:");
/* special handling of interface event */
if (event->code == BRCMF_E_IF) {
brcmf_fweh_handle_if_event(drvr, &emsg, event->data);
goto event_free;
}
err = brcmf_fweh_call_event_handler(ifp, event->code, &emsg,
event->data);
if (err) {
brcmf_dbg(ERROR, "event handler failed (%d)\n",
event->code);
err = 0;
}
event_free:
kfree(event);
}
}
/**
* brcmf_fweh_attach() - initialize firmware event handling.
*
* @drvr: driver information object.
*/
void brcmf_fweh_attach(struct brcmf_pub *drvr)
{
struct brcmf_fweh_info *fweh = &drvr->fweh;
INIT_WORK(&fweh->event_work, brcmf_fweh_event_worker);
spin_lock_init(&fweh->evt_q_lock);
INIT_LIST_HEAD(&fweh->event_q);
}
/**
* brcmf_fweh_detach() - cleanup firmware event handling.
*
* @drvr: driver information object.
*/
void brcmf_fweh_detach(struct brcmf_pub *drvr)
{
struct brcmf_fweh_info *fweh = &drvr->fweh;
struct brcmf_if *ifp = drvr->iflist[0];
s8 eventmask[BRCMF_EVENTING_MASK_LEN];
if (ifp) {
/* clear all events */
memset(eventmask, 0, BRCMF_EVENTING_MASK_LEN);
(void)brcmf_fil_iovar_data_set(ifp, "event_msgs",
eventmask,
BRCMF_EVENTING_MASK_LEN);
}
/* cancel the worker */
cancel_work_sync(&fweh->event_work);
WARN_ON(!list_empty(&fweh->event_q));
memset(fweh->evt_handler, 0, sizeof(fweh->evt_handler));
}
/**
* brcmf_fweh_register() - register handler for given event code.
*
* @drvr: driver information object.
* @code: event code.
* @handler: handler for the given event code.
*/
int brcmf_fweh_register(struct brcmf_pub *drvr, enum brcmf_fweh_event_code code,
brcmf_fweh_handler_t handler)
{
if (drvr->fweh.evt_handler[code]) {
brcmf_dbg(ERROR, "event code %d already registered\n", code);
return -ENOSPC;
}
drvr->fweh.evt_handler[code] = handler;
brcmf_dbg(TRACE, "event handler registered for %s\n",
brcmf_fweh_event_name(code));
return 0;
}
/**
* brcmf_fweh_unregister() - remove handler for given code.
*
* @drvr: driver information object.
* @code: event code.
*/
void brcmf_fweh_unregister(struct brcmf_pub *drvr,
enum brcmf_fweh_event_code code)
{
brcmf_dbg(TRACE, "event handler cleared for %s\n",
brcmf_fweh_event_name(code));
drvr->fweh.evt_handler[code] = NULL;
}
/**
* brcmf_fweh_activate_events() - enables firmware events registered.
*
* @ifp: primary interface object.
*/
int brcmf_fweh_activate_events(struct brcmf_if *ifp)
{
int i, err;
s8 eventmask[BRCMF_EVENTING_MASK_LEN];
for (i = 0; i < BRCMF_E_LAST; i++) {
if (ifp->drvr->fweh.evt_handler[i]) {
brcmf_dbg(EVENT, "enable event %s\n",
brcmf_fweh_event_name(i));
setbit(eventmask, i);
}
}
/* want to handle IF event as well */
brcmf_dbg(EVENT, "enable event IF\n");
setbit(eventmask, BRCMF_E_IF);
err = brcmf_fil_iovar_data_set(ifp, "event_msgs",
eventmask, BRCMF_EVENTING_MASK_LEN);
if (err)
brcmf_dbg(ERROR, "Set event_msgs error (%d)\n", err);
return err;
}
/**
* brcmf_fweh_process_event() - process skb as firmware event.
*
* @drvr: driver information object.
* @event_packet: event packet to process.
* @ifidx: index of the firmware interface (may change).
*
* If the packet buffer contains a firmware event message it will
* dispatch the event to a registered handler (using worker).
*/
void brcmf_fweh_process_event(struct brcmf_pub *drvr,
struct brcmf_event *event_packet, u8 *ifidx)
{
enum brcmf_fweh_event_code code;
struct brcmf_fweh_info *fweh = &drvr->fweh;
struct brcmf_fweh_queue_item *event;
gfp_t alloc_flag = GFP_KERNEL;
void *data;
u32 datalen;
/* get event info */
code = get_unaligned_be32(&event_packet->msg.event_type);
datalen = get_unaligned_be32(&event_packet->msg.datalen);
*ifidx = event_packet->msg.ifidx;
data = &event_packet[1];
if (code >= BRCMF_E_LAST)
return;
if (code != BRCMF_E_IF && !fweh->evt_handler[code])
return;
if (in_interrupt())
alloc_flag = GFP_ATOMIC;
event = kzalloc(sizeof(*event) + datalen, alloc_flag);
if (!event)
return;
event->code = code;
event->ifidx = *ifidx;
/* use memcpy to get aligned event message */
memcpy(&event->emsg, &event_packet->msg, sizeof(event->emsg));
memcpy(event->data, data, datalen);
memcpy(event->ifaddr, event_packet->eth.h_dest, ETH_ALEN);
brcmf_fweh_queue_event(fweh, event);
}

View File

@ -0,0 +1,207 @@
/*
* Copyright (c) 2012 Broadcom Corporation
*
* 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 FWEH_H_
#define FWEH_H_
#include <asm/unaligned.h>
#include <linux/skbuff.h>
#include <linux/if_ether.h>
#include <linux/if.h>
/* formward declarations */
struct brcmf_pub;
struct brcmf_if;
struct brcmf_cfg80211_info;
struct brcmf_event;
/* firmware event codes sent by the dongle */
enum brcmf_fweh_event_code {
BRCMF_E_SET_SSID = 0,
BRCMF_E_JOIN = 1,
BRCMF_E_START = 2,
BRCMF_E_AUTH = 3,
BRCMF_E_AUTH_IND = 4,
BRCMF_E_DEAUTH = 5,
BRCMF_E_DEAUTH_IND = 6,
BRCMF_E_ASSOC = 7,
BRCMF_E_ASSOC_IND = 8,
BRCMF_E_REASSOC = 9,
BRCMF_E_REASSOC_IND = 10,
BRCMF_E_DISASSOC = 11,
BRCMF_E_DISASSOC_IND = 12,
BRCMF_E_QUIET_START = 13,
BRCMF_E_QUIET_END = 14,
BRCMF_E_BEACON_RX = 15,
BRCMF_E_LINK = 16,
BRCMF_E_MIC_ERROR = 17,
BRCMF_E_NDIS_LINK = 18,
BRCMF_E_ROAM = 19,
BRCMF_E_TXFAIL = 20,
BRCMF_E_PMKID_CACHE = 21,
BRCMF_E_RETROGRADE_TSF = 22,
BRCMF_E_PRUNE = 23,
BRCMF_E_AUTOAUTH = 24,
BRCMF_E_EAPOL_MSG = 25,
BRCMF_E_SCAN_COMPLETE = 26,
BRCMF_E_ADDTS_IND = 27,
BRCMF_E_DELTS_IND = 28,
BRCMF_E_BCNSENT_IND = 29,
BRCMF_E_BCNRX_MSG = 30,
BRCMF_E_BCNLOST_MSG = 31,
BRCMF_E_ROAM_PREP = 32,
BRCMF_E_PFN_NET_FOUND = 33,
BRCMF_E_PFN_NET_LOST = 34,
BRCMF_E_RESET_COMPLETE = 35,
BRCMF_E_JOIN_START = 36,
BRCMF_E_ROAM_START = 37,
BRCMF_E_ASSOC_START = 38,
BRCMF_E_IBSS_ASSOC = 39,
BRCMF_E_RADIO = 40,
BRCMF_E_PSM_WATCHDOG = 41,
BRCMF_E_PROBREQ_MSG = 44,
BRCMF_E_SCAN_CONFIRM_IND = 45,
BRCMF_E_PSK_SUP = 46,
BRCMF_E_COUNTRY_CODE_CHANGED = 47,
BRCMF_E_EXCEEDED_MEDIUM_TIME = 48,
BRCMF_E_ICV_ERROR = 49,
BRCMF_E_UNICAST_DECODE_ERROR = 50,
BRCMF_E_MULTICAST_DECODE_ERROR = 51,
BRCMF_E_TRACE = 52,
BRCMF_E_IF = 54,
BRCMF_E_RSSI = 56,
BRCMF_E_PFN_SCAN_COMPLETE = 57,
BRCMF_E_EXTLOG_MSG = 58,
BRCMF_E_ACTION_FRAME = 59,
BRCMF_E_ACTION_FRAME_COMPLETE = 60,
BRCMF_E_PRE_ASSOC_IND = 61,
BRCMF_E_PRE_REASSOC_IND = 62,
BRCMF_E_CHANNEL_ADOPTED = 63,
BRCMF_E_AP_STARTED = 64,
BRCMF_E_DFS_AP_STOP = 65,
BRCMF_E_DFS_AP_RESUME = 66,
BRCMF_E_ESCAN_RESULT = 69,
BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE = 70,
BRCMF_E_DCS_REQUEST = 73,
BRCMF_E_FIFO_CREDIT_MAP = 74,
BRCMF_E_LAST
};
/* flags field values in struct brcmf_event_msg */
#define BRCMF_EVENT_MSG_LINK 0x01
#define BRCMF_EVENT_MSG_FLUSHTXQ 0x02
#define BRCMF_EVENT_MSG_GROUP 0x04
/**
* definitions for event packet validation.
*/
#define BRCMF_EVENT_OUI_OFFSET 19
#define BRCM_OUI "\x00\x10\x18"
#define DOT11_OUI_LEN 3
#define BCMILCP_BCM_SUBTYPE_EVENT 1
/**
* struct brcmf_event_msg - firmware event message.
*
* @version: version information.
* @flags: event flags.
* @event_code: firmware event code.
* @status: status information.
* @reason: reason code.
* @auth_type: authentication type.
* @datalen: lenght of event data buffer.
* @addr: ether address.
* @ifname: interface name.
* @ifidx: interface index.
* @bsscfgidx: bsscfg index.
*/
struct brcmf_event_msg {
u16 version;
u16 flags;
u32 event_code;
u32 status;
u32 reason;
s32 auth_type;
u32 datalen;
u8 addr[ETH_ALEN];
char ifname[IFNAMSIZ];
u8 ifidx;
u8 bsscfgidx;
};
typedef int (*brcmf_fweh_handler_t)(struct brcmf_if *ifp,
const struct brcmf_event_msg *evtmsg,
void *data);
/**
* struct brcmf_fweh_info - firmware event handling information.
*
* @event_work: event worker.
* @evt_q_lock: lock for event queue protection.
* @event_q: event queue.
* @evt_handler: registered event handlers.
*/
struct brcmf_fweh_info {
struct work_struct event_work;
struct spinlock evt_q_lock;
struct list_head event_q;
int (*evt_handler[BRCMF_E_LAST])(struct brcmf_if *ifp,
const struct brcmf_event_msg *evtmsg,
void *data);
};
void brcmf_fweh_attach(struct brcmf_pub *drvr);
void brcmf_fweh_detach(struct brcmf_pub *drvr);
int brcmf_fweh_register(struct brcmf_pub *drvr, enum brcmf_fweh_event_code code,
int (*handler)(struct brcmf_if *ifp,
const struct brcmf_event_msg *evtmsg,
void *data));
void brcmf_fweh_unregister(struct brcmf_pub *drvr,
enum brcmf_fweh_event_code code);
int brcmf_fweh_activate_events(struct brcmf_if *ifp);
void brcmf_fweh_process_event(struct brcmf_pub *drvr,
struct brcmf_event *event_packet, u8 *ifidx);
static inline void brcmf_fweh_process_skb(struct brcmf_pub *drvr,
struct sk_buff *skb, u8 *ifidx)
{
struct brcmf_event *event_packet;
u8 *data;
u16 usr_stype;
/* only process events when protocol matches */
if (skb->protocol != cpu_to_be16(ETH_P_LINK_CTL))
return;
/* check for BRCM oui match */
event_packet = (struct brcmf_event *)skb_mac_header(skb);
data = (u8 *)event_packet;
data += BRCMF_EVENT_OUI_OFFSET;
if (memcmp(BRCM_OUI, data, DOT11_OUI_LEN))
return;
/* final match on usr_subtype */
data += DOT11_OUI_LEN;
usr_stype = get_unaligned_be16(data);
if (usr_stype != BCMILCP_BCM_SUBTYPE_EVENT)
return;
brcmf_fweh_process_event(drvr, event_packet, ifidx);
}
#endif /* FWEH_H_ */

View File

@ -20,7 +20,6 @@
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <defs.h>
#include <brcmu_utils.h>
#include <brcmu_wifi.h>
#include "dhd.h"
@ -29,13 +28,16 @@
#include "fwil.h"
#define MAX_HEX_DUMP_LEN 64
static s32
brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set)
{
struct brcmf_pub *drvr = ifp->drvr;
s32 err;
if (drvr->bus_if->state == BRCMF_BUS_DOWN) {
if (drvr->bus_if->state != BRCMF_BUS_DATA) {
brcmf_dbg(ERROR, "bus is down. we have nothing to do.\n");
return -EIO;
}
@ -64,7 +66,8 @@ brcmf_fil_cmd_data_set(struct brcmf_if *ifp, u32 cmd, void *data, u32 len)
mutex_lock(&ifp->drvr->proto_block);
brcmf_dbg(FIL, "cmd=%d, len=%d\n", cmd, len);
brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, len, "data");
brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
min_t(uint, len, MAX_HEX_DUMP_LEN), "data");
err = brcmf_fil_cmd_data(ifp, cmd, data, len, true);
mutex_unlock(&ifp->drvr->proto_block);
@ -81,7 +84,8 @@ brcmf_fil_cmd_data_get(struct brcmf_if *ifp, u32 cmd, void *data, u32 len)
err = brcmf_fil_cmd_data(ifp, cmd, data, len, false);
brcmf_dbg(FIL, "cmd=%d, len=%d\n", cmd, len);
brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, len, "data");
brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
min_t(uint, len, MAX_HEX_DUMP_LEN), "data");
mutex_unlock(&ifp->drvr->proto_block);
@ -147,7 +151,8 @@ brcmf_fil_iovar_data_set(struct brcmf_if *ifp, char *name, void *data,
mutex_lock(&drvr->proto_block);
brcmf_dbg(FIL, "name=%s, len=%d\n", name, len);
brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, len, "data");
brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
min_t(uint, len, MAX_HEX_DUMP_LEN), "data");
buflen = brcmf_create_iovar(name, data, len, drvr->proto_buf,
sizeof(drvr->proto_buf));
@ -186,7 +191,8 @@ brcmf_fil_iovar_data_get(struct brcmf_if *ifp, char *name, void *data,
}
brcmf_dbg(FIL, "name=%s, len=%d\n", name, len);
brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, len, "data");
brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
min_t(uint, len, MAX_HEX_DUMP_LEN), "data");
mutex_unlock(&drvr->proto_block);
return err;
@ -268,7 +274,8 @@ brcmf_fil_bsscfg_data_set(struct brcmf_if *ifp, char *name,
mutex_lock(&drvr->proto_block);
brcmf_dbg(FIL, "bssidx=%d, name=%s, len=%d\n", ifp->bssidx, name, len);
brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, len, "data");
brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
min_t(uint, len, MAX_HEX_DUMP_LEN), "data");
buflen = brcmf_create_bsscfg(ifp->bssidx, name, data, len,
drvr->proto_buf, sizeof(drvr->proto_buf));
@ -294,7 +301,7 @@ brcmf_fil_bsscfg_data_get(struct brcmf_if *ifp, char *name,
mutex_lock(&drvr->proto_block);
buflen = brcmf_create_bsscfg(ifp->bssidx, name, NULL, len,
buflen = brcmf_create_bsscfg(ifp->bssidx, name, data, len,
drvr->proto_buf, sizeof(drvr->proto_buf));
if (buflen) {
err = brcmf_fil_cmd_data(ifp, BRCMF_C_GET_VAR, drvr->proto_buf,
@ -306,7 +313,8 @@ brcmf_fil_bsscfg_data_get(struct brcmf_if *ifp, char *name,
brcmf_dbg(ERROR, "Creating bsscfg failed\n");
}
brcmf_dbg(FIL, "bssidx=%d, name=%s, len=%d\n", ifp->bssidx, name, len);
brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, len, "data");
brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
min_t(uint, len, MAX_HEX_DUMP_LEN), "data");
mutex_unlock(&drvr->proto_block);
return err;

View File

@ -14,24 +14,12 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kthread.h>
#include <linux/slab.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/spinlock.h>
#include <linux/ethtool.h>
#include <linux/fcntl.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/firmware.h>
#include <linux/usb.h>
#include <linux/vmalloc.h>
#include <net/cfg80211.h>
#include <defs.h>
#include <brcmu_utils.h>
#include <brcmu_wifi.h>
#include <dhd_bus.h>
@ -42,13 +30,11 @@
#define IOCTL_RESP_TIMEOUT 2000
#define BRCMF_USB_DLIMAGE_SPINWAIT 100 /* in unit of ms */
#define BRCMF_USB_DLIMAGE_LIMIT 500 /* spinwait limit (ms) */
#define BRCMF_USB_RESET_GETVER_SPINWAIT 100 /* in unit of ms */
#define BRCMF_USB_RESET_GETVER_LOOP_CNT 10
#define BRCMF_POSTBOOT_ID 0xA123 /* ID to detect if dongle
has boot up */
#define BRCMF_USB_RESETCFG_SPINWAIT 1 /* wait after resetcfg (ms) */
#define BRCMF_USB_NRXQ 50
#define BRCMF_USB_NTXQ 50
@ -69,16 +55,6 @@
#define BRCMF_USB_43236_FW_NAME "brcm/brcmfmac43236b.bin"
#define BRCMF_USB_43242_FW_NAME "brcm/brcmfmac43242a.bin"
enum usbdev_suspend_state {
USBOS_SUSPEND_STATE_DEVICE_ACTIVE = 0, /* Device is busy, won't allow
suspend */
USBOS_SUSPEND_STATE_SUSPEND_PENDING, /* Device is idle, can be
* suspended. Wating PM to
* suspend the device
*/
USBOS_SUSPEND_STATE_SUSPENDED /* Device suspended */
};
struct brcmf_usb_image {
struct list_head list;
s8 *fwname;
@ -99,10 +75,8 @@ struct brcmf_usbdev_info {
struct list_head rx_postq;
struct list_head tx_freeq;
struct list_head tx_postq;
enum usbdev_suspend_state suspend_state;
uint rx_pipe, tx_pipe, intr_pipe, rx_pipe2;
bool activity;
int rx_low_watermark;
int tx_low_watermark;
int tx_high_watermark;
@ -170,6 +144,7 @@ static void brcmf_usb_ioctl_resp_wake(struct brcmf_usbdev_info *devinfo)
static void
brcmf_usb_ctl_complete(struct brcmf_usbdev_info *devinfo, int type, int status)
{
brcmf_dbg(USB, "Enter, status=%d\n", status);
if (unlikely(devinfo == NULL))
return;
@ -197,6 +172,7 @@ brcmf_usb_ctlread_complete(struct urb *urb)
struct brcmf_usbdev_info *devinfo =
(struct brcmf_usbdev_info *)urb->context;
brcmf_dbg(USB, "Enter\n");
devinfo->ctl_urb_actual_length = urb->actual_length;
brcmf_usb_ctl_complete(devinfo, BRCMF_USB_CBCTL_READ,
urb->status);
@ -208,33 +184,22 @@ brcmf_usb_ctlwrite_complete(struct urb *urb)
struct brcmf_usbdev_info *devinfo =
(struct brcmf_usbdev_info *)urb->context;
brcmf_dbg(USB, "Enter\n");
brcmf_usb_ctl_complete(devinfo, BRCMF_USB_CBCTL_WRITE,
urb->status);
}
static int brcmf_usb_pnp(struct brcmf_usbdev_info *devinfo, uint state)
{
return 0;
}
static int
brcmf_usb_send_ctl(struct brcmf_usbdev_info *devinfo, u8 *buf, int len)
{
int ret;
u16 size;
brcmf_dbg(USB, "Enter\n");
if (devinfo == NULL || buf == NULL ||
len == 0 || devinfo->ctl_urb == NULL)
return -EINVAL;
/* If the USB/HSIC bus in sleep state, wake it up */
if (devinfo->suspend_state == USBOS_SUSPEND_STATE_SUSPENDED)
if (brcmf_usb_pnp(devinfo, BCMFMAC_USB_PNP_RESUME) != 0) {
brcmf_dbg(ERROR, "Could not Resume the bus!\n");
return -EIO;
}
devinfo->activity = true;
size = len;
devinfo->ctl_write.wLength = cpu_to_le16p(&size);
devinfo->ctl_urb->transfer_buffer_length = size;
@ -262,6 +227,7 @@ brcmf_usb_recv_ctl(struct brcmf_usbdev_info *devinfo, u8 *buf, int len)
int ret;
u16 size;
brcmf_dbg(USB, "Enter\n");
if ((devinfo == NULL) || (buf == NULL) || (len == 0)
|| (devinfo->ctl_urb == NULL))
return -EINVAL;
@ -295,10 +261,9 @@ static int brcmf_usb_tx_ctlpkt(struct device *dev, u8 *buf, u32 len)
int timeout = 0;
struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
if (devinfo->bus_pub.state != BCMFMAC_USB_STATE_UP) {
/* TODO: handle suspend/resume */
brcmf_dbg(USB, "Enter\n");
if (devinfo->bus_pub.state != BRCMFMAC_USB_STATE_UP)
return -EIO;
}
if (test_and_set_bit(0, &devinfo->ctl_op))
return -EIO;
@ -325,10 +290,10 @@ static int brcmf_usb_rx_ctlpkt(struct device *dev, u8 *buf, u32 len)
int timeout = 0;
struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
if (devinfo->bus_pub.state != BCMFMAC_USB_STATE_UP) {
/* TODO: handle suspend/resume */
brcmf_dbg(USB, "Enter\n");
if (devinfo->bus_pub.state != BRCMFMAC_USB_STATE_UP)
return -EIO;
}
if (test_and_set_bit(0, &devinfo->ctl_op))
return -EIO;
@ -453,6 +418,8 @@ static void brcmf_usb_tx_complete(struct urb *urb)
struct brcmf_usbreq *req = (struct brcmf_usbreq *)urb->context;
struct brcmf_usbdev_info *devinfo = req->devinfo;
brcmf_dbg(USB, "Enter, urb->status=%d, skb=%p\n", urb->status,
req->skb);
brcmf_usb_del_fromq(devinfo, req);
if (urb->status == 0)
devinfo->bus_pub.bus->dstats.tx_packets++;
@ -478,6 +445,7 @@ static void brcmf_usb_rx_complete(struct urb *urb)
struct sk_buff *skb;
int ifidx = 0;
brcmf_dbg(USB, "Enter, urb->status=%d\n", urb->status);
brcmf_usb_del_fromq(devinfo, req);
skb = req->skb;
req->skb = NULL;
@ -491,7 +459,7 @@ static void brcmf_usb_rx_complete(struct urb *urb)
return;
}
if (devinfo->bus_pub.state == BCMFMAC_USB_STATE_UP) {
if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP) {
skb_put(skb, urb->actual_length);
if (brcmf_proto_hdrpull(devinfo->dev, &ifidx, skb) != 0) {
brcmf_dbg(ERROR, "rx protocol error\n");
@ -544,8 +512,8 @@ static void brcmf_usb_rx_fill_all(struct brcmf_usbdev_info *devinfo)
{
struct brcmf_usbreq *req;
if (devinfo->bus_pub.state != BCMFMAC_USB_STATE_UP) {
brcmf_dbg(ERROR, "bus is not up\n");
if (devinfo->bus_pub.state != BRCMFMAC_USB_STATE_UP) {
brcmf_dbg(ERROR, "bus is not up=%d\n", devinfo->bus_pub.state);
return;
}
while ((req = brcmf_usb_deq(devinfo, &devinfo->rx_freeq, NULL)) != NULL)
@ -558,29 +526,24 @@ brcmf_usb_state_change(struct brcmf_usbdev_info *devinfo, int state)
struct brcmf_bus *bcmf_bus = devinfo->bus_pub.bus;
int old_state;
brcmf_dbg(USB, "Enter, current state=%d, new state=%d\n",
devinfo->bus_pub.state, state);
if (devinfo->bus_pub.state == state)
return;
old_state = devinfo->bus_pub.state;
brcmf_dbg(TRACE, "dbus state change from %d to to %d\n",
old_state, state);
/* Don't update state if it's PnP firmware re-download */
if (state != BCMFMAC_USB_STATE_PNP_FWDL) /* TODO */
devinfo->bus_pub.state = state;
if ((old_state == BCMFMAC_USB_STATE_SLEEP)
&& (state == BCMFMAC_USB_STATE_UP)) {
brcmf_usb_rx_fill_all(devinfo);
}
devinfo->bus_pub.state = state;
/* update state of upper layer */
if (state == BCMFMAC_USB_STATE_DOWN) {
brcmf_dbg(INFO, "DBUS is down\n");
if (state == BRCMFMAC_USB_STATE_DOWN) {
brcmf_dbg(USB, "DBUS is down\n");
bcmf_bus->state = BRCMF_BUS_DOWN;
} else if (state == BRCMFMAC_USB_STATE_UP) {
brcmf_dbg(USB, "DBUS is up\n");
bcmf_bus->state = BRCMF_BUS_DATA;
} else {
brcmf_dbg(INFO, "DBUS current state=%d\n", state);
brcmf_dbg(USB, "DBUS current state=%d\n", state);
}
}
@ -589,30 +552,32 @@ brcmf_usb_intr_complete(struct urb *urb)
{
struct brcmf_usbdev_info *devinfo =
(struct brcmf_usbdev_info *)urb->context;
bool killed;
int err;
brcmf_dbg(USB, "Enter, urb->status=%d\n", urb->status);
if (devinfo == NULL)
return;
if (unlikely(urb->status)) {
if (devinfo->suspend_state ==
USBOS_SUSPEND_STATE_SUSPEND_PENDING)
killed = true;
if ((urb->status == -ENOENT && (!killed))
|| urb->status == -ESHUTDOWN ||
urb->status == -ENODEV) {
brcmf_usb_state_change(devinfo, BCMFMAC_USB_STATE_DOWN);
if (urb->status == -ENOENT ||
urb->status == -ESHUTDOWN ||
urb->status == -ENODEV) {
brcmf_usb_state_change(devinfo,
BRCMFMAC_USB_STATE_DOWN);
}
}
if (devinfo->bus_pub.state == BCMFMAC_USB_STATE_DOWN) {
if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_DOWN) {
brcmf_dbg(ERROR, "intr cb when DBUS down, ignoring\n");
return;
}
if (devinfo->bus_pub.state == BCMFMAC_USB_STATE_UP)
usb_submit_urb(devinfo->intr_urb, GFP_ATOMIC);
if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP) {
err = usb_submit_urb(devinfo->intr_urb, GFP_ATOMIC);
if (err)
brcmf_dbg(ERROR, "usb_submit_urb, err=%d\n", err);
}
}
static int brcmf_usb_tx(struct device *dev, struct sk_buff *skb)
@ -621,10 +586,9 @@ static int brcmf_usb_tx(struct device *dev, struct sk_buff *skb)
struct brcmf_usbreq *req;
int ret;
if (devinfo->bus_pub.state != BCMFMAC_USB_STATE_UP) {
/* TODO: handle suspend/resume */
brcmf_dbg(USB, "Enter, skb=%p\n", skb);
if (devinfo->bus_pub.state != BRCMFMAC_USB_STATE_UP)
return -EIO;
}
req = brcmf_usb_deq(devinfo, &devinfo->tx_freeq,
&devinfo->tx_freecount);
@ -664,25 +628,16 @@ static int brcmf_usb_up(struct device *dev)
{
struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
u16 ifnum;
int ret;
if (devinfo->bus_pub.state == BCMFMAC_USB_STATE_UP)
brcmf_dbg(USB, "Enter\n");
if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP)
return 0;
/* If the USB/HSIC bus in sleep state, wake it up */
if (devinfo->suspend_state == USBOS_SUSPEND_STATE_SUSPENDED) {
if (brcmf_usb_pnp(devinfo, BCMFMAC_USB_PNP_RESUME) != 0) {
brcmf_dbg(ERROR, "Could not Resume the bus!\n");
return -EIO;
}
}
devinfo->activity = true;
/* Success, indicate devinfo is fully up */
brcmf_usb_state_change(devinfo, BCMFMAC_USB_STATE_UP);
brcmf_usb_state_change(devinfo, BRCMFMAC_USB_STATE_UP);
if (devinfo->intr_urb) {
int ret;
usb_fill_int_urb(devinfo->intr_urb, devinfo->usbdev,
devinfo->intr_pipe,
&devinfo->intr,
@ -727,14 +682,14 @@ static void brcmf_usb_down(struct device *dev)
{
struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
brcmf_dbg(USB, "Enter\n");
if (devinfo == NULL)
return;
brcmf_dbg(TRACE, "enter\n");
if (devinfo->bus_pub.state == BCMFMAC_USB_STATE_DOWN)
if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_DOWN)
return;
brcmf_usb_state_change(devinfo, BCMFMAC_USB_STATE_DOWN);
brcmf_usb_state_change(devinfo, BRCMFMAC_USB_STATE_DOWN);
if (devinfo->intr_urb)
usb_kill_urb(devinfo->intr_urb);
@ -808,27 +763,25 @@ brcmf_usb_dlneeded(struct brcmf_usbdev_info *devinfo)
struct bootrom_id_le id;
u32 chipid, chiprev;
brcmf_dbg(TRACE, "enter\n");
brcmf_dbg(USB, "Enter\n");
if (devinfo == NULL)
return false;
/* Check if firmware downloaded already by querying runtime ID */
id.chip = cpu_to_le32(0xDEAD);
brcmf_usb_dl_cmd(devinfo, DL_GETVER, &id,
sizeof(struct bootrom_id_le));
brcmf_usb_dl_cmd(devinfo, DL_GETVER, &id, sizeof(id));
chipid = le32_to_cpu(id.chip);
chiprev = le32_to_cpu(id.chiprev);
if ((chipid & 0x4300) == 0x4300)
brcmf_dbg(INFO, "chip %x rev 0x%x\n", chipid, chiprev);
brcmf_dbg(USB, "chip %x rev 0x%x\n", chipid, chiprev);
else
brcmf_dbg(INFO, "chip %d rev 0x%x\n", chipid, chiprev);
brcmf_dbg(USB, "chip %d rev 0x%x\n", chipid, chiprev);
if (chipid == BRCMF_POSTBOOT_ID) {
brcmf_dbg(INFO, "firmware already downloaded\n");
brcmf_usb_dl_cmd(devinfo, DL_RESETCFG, &id,
sizeof(struct bootrom_id_le));
brcmf_dbg(USB, "firmware already downloaded\n");
brcmf_usb_dl_cmd(devinfo, DL_RESETCFG, &id, sizeof(id));
return false;
} else {
devinfo->bus_pub.devid = chipid;
@ -841,38 +794,29 @@ static int
brcmf_usb_resetcfg(struct brcmf_usbdev_info *devinfo)
{
struct bootrom_id_le id;
u16 wait = 0, wait_time;
u32 loop_cnt;
brcmf_dbg(TRACE, "enter\n");
brcmf_dbg(USB, "Enter\n");
if (devinfo == NULL)
return -EINVAL;
/* Give dongle chance to boot */
wait_time = BRCMF_USB_DLIMAGE_SPINWAIT;
while (wait < BRCMF_USB_DLIMAGE_LIMIT) {
mdelay(wait_time);
wait += wait_time;
loop_cnt = 0;
do {
mdelay(BRCMF_USB_RESET_GETVER_SPINWAIT);
loop_cnt++;
id.chip = cpu_to_le32(0xDEAD); /* Get the ID */
brcmf_usb_dl_cmd(devinfo, DL_GETVER, &id,
sizeof(struct bootrom_id_le));
brcmf_usb_dl_cmd(devinfo, DL_GETVER, &id, sizeof(id));
if (id.chip == cpu_to_le32(BRCMF_POSTBOOT_ID))
break;
}
} while (loop_cnt < BRCMF_USB_RESET_GETVER_LOOP_CNT);
if (id.chip == cpu_to_le32(BRCMF_POSTBOOT_ID)) {
brcmf_dbg(INFO, "download done %d ms postboot chip 0x%x/rev 0x%x\n",
wait, le32_to_cpu(id.chip), le32_to_cpu(id.chiprev));
brcmf_dbg(USB, "postboot chip 0x%x/rev 0x%x\n",
le32_to_cpu(id.chip), le32_to_cpu(id.chiprev));
brcmf_usb_dl_cmd(devinfo, DL_RESETCFG, &id,
sizeof(struct bootrom_id_le));
/* XXX this wait may not be necessary */
mdelay(BRCMF_USB_RESETCFG_SPINWAIT);
brcmf_usb_dl_cmd(devinfo, DL_RESETCFG, &id, sizeof(id));
return 0;
} else {
brcmf_dbg(ERROR, "Cannot talk to Dongle. Firmware is not UP, %d ms\n",
wait);
BRCMF_USB_RESET_GETVER_SPINWAIT * loop_cnt);
return -EINVAL;
}
}
@ -911,7 +855,8 @@ brcmf_usb_dl_writeimage(struct brcmf_usbdev_info *devinfo, u8 *fw, int fwlen)
struct rdl_state_le state;
u32 rdlstate, rdlbytes;
int err = 0;
brcmf_dbg(TRACE, "fw %p, len %d\n", fw, fwlen);
brcmf_dbg(USB, "Enter, fw %p, len %d\n", fw, fwlen);
bulkchunk = kmalloc(RDL_CHUNK, GFP_ATOMIC);
if (bulkchunk == NULL) {
@ -986,7 +931,7 @@ brcmf_usb_dl_writeimage(struct brcmf_usbdev_info *devinfo, u8 *fw, int fwlen)
fail:
kfree(bulkchunk);
brcmf_dbg(TRACE, "err=%d\n", err);
brcmf_dbg(USB, "Exit, err=%d\n", err);
return err;
}
@ -994,7 +939,7 @@ static int brcmf_usb_dlstart(struct brcmf_usbdev_info *devinfo, u8 *fw, int len)
{
int err;
brcmf_dbg(TRACE, "enter\n");
brcmf_dbg(USB, "Enter\n");
if (devinfo == NULL)
return -EINVAL;
@ -1004,10 +949,10 @@ static int brcmf_usb_dlstart(struct brcmf_usbdev_info *devinfo, u8 *fw, int len)
err = brcmf_usb_dl_writeimage(devinfo, fw, len);
if (err == 0)
devinfo->bus_pub.state = BCMFMAC_USB_STATE_DL_DONE;
devinfo->bus_pub.state = BRCMFMAC_USB_STATE_DL_DONE;
else
devinfo->bus_pub.state = BCMFMAC_USB_STATE_DL_PENDING;
brcmf_dbg(TRACE, "exit: err=%d\n", err);
devinfo->bus_pub.state = BRCMFMAC_USB_STATE_DL_FAIL;
brcmf_dbg(USB, "Exit, err=%d\n", err);
return err;
}
@ -1016,7 +961,7 @@ static int brcmf_usb_dlrun(struct brcmf_usbdev_info *devinfo)
{
struct rdl_state_le state;
brcmf_dbg(TRACE, "enter\n");
brcmf_dbg(USB, "Enter\n");
if (!devinfo)
return -EINVAL;
@ -1039,7 +984,7 @@ static int brcmf_usb_dlrun(struct brcmf_usbdev_info *devinfo)
brcmf_dbg(ERROR, "Dongle not runnable\n");
return -EINVAL;
}
brcmf_dbg(TRACE, "exit\n");
brcmf_dbg(USB, "Exit\n");
return 0;
}
@ -1066,7 +1011,7 @@ brcmf_usb_fw_download(struct brcmf_usbdev_info *devinfo)
int devid, chiprev;
int err;
brcmf_dbg(TRACE, "enter\n");
brcmf_dbg(USB, "Enter\n");
if (devinfo == NULL)
return -ENODEV;
@ -1094,7 +1039,7 @@ brcmf_usb_fw_download(struct brcmf_usbdev_info *devinfo)
static void brcmf_usb_detach(struct brcmf_usbdev_info *devinfo)
{
brcmf_dbg(TRACE, "devinfo %p\n", devinfo);
brcmf_dbg(USB, "Enter, devinfo %p\n", devinfo);
/* free the URBS */
brcmf_usb_free_q(&devinfo->rx_freeq, false);
@ -1129,6 +1074,7 @@ static int check_file(const u8 *headers)
struct trx_header_le *trx;
int actual_len = -1;
brcmf_dbg(USB, "Enter\n");
/* Extract trx header */
trx = (struct trx_header_le *) headers;
if (trx->magic != cpu_to_le32(TRX_MAGIC))
@ -1150,6 +1096,7 @@ static int brcmf_usb_get_fw(struct brcmf_usbdev_info *devinfo)
struct brcmf_usb_image *fw_image;
int err;
brcmf_dbg(USB, "Enter\n");
switch (devinfo->bus_pub.devid) {
case 43143:
fwname = BRCMF_USB_43143_FW_NAME;
@ -1166,7 +1113,7 @@ static int brcmf_usb_get_fw(struct brcmf_usbdev_info *devinfo)
return -EINVAL;
break;
}
brcmf_dbg(USB, "Loading FW %s\n", fwname);
list_for_each_entry(fw_image, &fw_image_list, list) {
if (fw_image->fwname == fwname) {
devinfo->image = fw_image->image;
@ -1211,10 +1158,13 @@ static
struct brcmf_usbdev *brcmf_usb_attach(struct brcmf_usbdev_info *devinfo,
int nrxq, int ntxq)
{
brcmf_dbg(USB, "Enter\n");
devinfo->bus_pub.nrxq = nrxq;
devinfo->rx_low_watermark = nrxq / 2;
devinfo->bus_pub.devinfo = devinfo;
devinfo->bus_pub.ntxq = ntxq;
devinfo->bus_pub.state = BRCMFMAC_USB_STATE_DOWN;
/* flow control when too many tx urbs posted */
devinfo->tx_low_watermark = ntxq / 4;
@ -1263,7 +1213,7 @@ struct brcmf_usbdev *brcmf_usb_attach(struct brcmf_usbdev_info *devinfo,
if (!brcmf_usb_dlneeded(devinfo))
return &devinfo->bus_pub;
brcmf_dbg(TRACE, "start fw downloading\n");
brcmf_dbg(USB, "Start fw downloading\n");
if (brcmf_usb_get_fw(devinfo))
goto error;
@ -1278,14 +1228,14 @@ error:
return NULL;
}
static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo,
const char *desc, u32 bustype, u32 hdrlen)
static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo)
{
struct brcmf_bus *bus = NULL;
struct brcmf_usbdev *bus_pub = NULL;
int ret;
struct device *dev = devinfo->dev;
brcmf_dbg(USB, "Enter\n");
bus_pub = brcmf_usb_attach(devinfo, BRCMF_USB_NRXQ, BRCMF_USB_NTXQ);
if (!bus_pub)
return -ENODEV;
@ -1302,14 +1252,13 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo,
bus->brcmf_bus_stop = brcmf_usb_down;
bus->brcmf_bus_txctl = brcmf_usb_tx_ctlpkt;
bus->brcmf_bus_rxctl = brcmf_usb_rx_ctlpkt;
bus->type = bustype;
bus->bus_priv.usb = bus_pub;
dev_set_drvdata(dev, bus);
/* Attach to the common driver interface */
ret = brcmf_attach(hdrlen, dev);
ret = brcmf_attach(0, dev);
if (ret) {
brcmf_dbg(ERROR, "dhd_attach failed\n");
brcmf_dbg(ERROR, "brcmf_attach failed\n");
goto fail;
}
@ -1333,7 +1282,7 @@ brcmf_usb_disconnect_cb(struct brcmf_usbdev_info *devinfo)
{
if (!devinfo)
return;
brcmf_dbg(TRACE, "enter: bus_pub %p\n", devinfo);
brcmf_dbg(USB, "Enter, bus_pub %p\n", devinfo);
brcmf_detach(devinfo->dev);
kfree(devinfo->bus_pub.bus);
@ -1351,7 +1300,7 @@ brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
u8 endpoint_num;
struct brcmf_usbdev_info *devinfo;
brcmf_dbg(TRACE, "enter\n");
brcmf_dbg(USB, "Enter\n");
devinfo = kzalloc(sizeof(*devinfo), GFP_ATOMIC);
if (devinfo == NULL)
@ -1452,11 +1401,11 @@ brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
devinfo->interval = IFEPDESC(usb, CONTROL_IF, 0).bInterval;
if (usb->speed == USB_SPEED_HIGH)
brcmf_dbg(INFO, "Broadcom high speed USB wireless device detected\n");
brcmf_dbg(USB, "Broadcom high speed USB wireless device detected\n");
else
brcmf_dbg(INFO, "Broadcom full speed USB wireless device detected\n");
brcmf_dbg(USB, "Broadcom full speed USB wireless device detected\n");
ret = brcmf_usb_probe_cb(devinfo, "", USB_BUS, 0);
ret = brcmf_usb_probe_cb(devinfo);
if (ret)
goto fail;
@ -1476,40 +1425,55 @@ brcmf_usb_disconnect(struct usb_interface *intf)
{
struct brcmf_usbdev_info *devinfo;
brcmf_dbg(TRACE, "enter\n");
brcmf_dbg(USB, "Enter\n");
devinfo = (struct brcmf_usbdev_info *)usb_get_intfdata(intf);
brcmf_usb_disconnect_cb(devinfo);
kfree(devinfo);
brcmf_dbg(USB, "Exit\n");
}
/*
* only need to signal the bus being down and update the suspend state.
* only need to signal the bus being down and update the state.
*/
static int brcmf_usb_suspend(struct usb_interface *intf, pm_message_t state)
{
struct usb_device *usb = interface_to_usbdev(intf);
struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev);
brcmf_dbg(TRACE, "enter\n");
devinfo->bus_pub.state = BCMFMAC_USB_STATE_DOWN;
devinfo->suspend_state = USBOS_SUSPEND_STATE_SUSPENDED;
brcmf_dbg(USB, "Enter\n");
devinfo->bus_pub.state = BRCMFMAC_USB_STATE_SLEEP;
brcmf_detach(&usb->dev);
return 0;
}
/*
* mark suspend state active and crank up the bus.
* (re-) start the bus.
*/
static int brcmf_usb_resume(struct usb_interface *intf)
{
struct usb_device *usb = interface_to_usbdev(intf);
struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev);
brcmf_dbg(TRACE, "enter\n");
devinfo->suspend_state = USBOS_SUSPEND_STATE_DEVICE_ACTIVE;
brcmf_bus_start(&usb->dev);
brcmf_dbg(USB, "Enter\n");
if (!brcmf_attach(0, devinfo->dev))
return brcmf_bus_start(&usb->dev);
return 0;
}
static int brcmf_usb_reset_resume(struct usb_interface *intf)
{
struct usb_device *usb = interface_to_usbdev(intf);
struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev);
brcmf_dbg(USB, "Enter\n");
if (!brcmf_usb_fw_download(devinfo))
return brcmf_usb_resume(intf);
return -EIO;
}
#define BRCMF_USB_VENDOR_ID_BROADCOM 0x0a5c
#define BRCMF_USB_DEVICE_ID_43143 0xbd1e
#define BRCMF_USB_DEVICE_ID_43236 0xbd17
@ -1529,7 +1493,6 @@ MODULE_FIRMWARE(BRCMF_USB_43143_FW_NAME);
MODULE_FIRMWARE(BRCMF_USB_43236_FW_NAME);
MODULE_FIRMWARE(BRCMF_USB_43242_FW_NAME);
/* TODO: suspend and resume entries */
static struct usb_driver brcmf_usbdrvr = {
.name = KBUILD_MODNAME,
.probe = brcmf_usb_probe,
@ -1537,6 +1500,7 @@ static struct usb_driver brcmf_usbdrvr = {
.id_table = brcmf_usb_devid_table,
.suspend = brcmf_usb_suspend,
.resume = brcmf_usb_resume,
.reset_resume = brcmf_usb_reset_resume,
.supports_autosuspend = 1,
.disable_hub_initiated_lpm = 1,
};
@ -1554,12 +1518,14 @@ static void brcmf_release_fw(struct list_head *q)
void brcmf_usb_exit(void)
{
brcmf_dbg(USB, "Enter\n");
usb_deregister(&brcmf_usbdrvr);
brcmf_release_fw(&fw_image_list);
}
void brcmf_usb_init(void)
{
brcmf_dbg(USB, "Enter\n");
INIT_LIST_HEAD(&fw_image_list);
usb_register(&brcmf_usbdrvr);
}

View File

@ -17,19 +17,11 @@
#define BRCMFMAC_USB_H
enum brcmf_usb_state {
BCMFMAC_USB_STATE_DL_PENDING,
BCMFMAC_USB_STATE_DL_DONE,
BCMFMAC_USB_STATE_UP,
BCMFMAC_USB_STATE_DOWN,
BCMFMAC_USB_STATE_PNP_FWDL,
BCMFMAC_USB_STATE_DISCONNECT,
BCMFMAC_USB_STATE_SLEEP
};
enum brcmf_usb_pnp_state {
BCMFMAC_USB_PNP_DISCONNECT,
BCMFMAC_USB_PNP_SLEEP,
BCMFMAC_USB_PNP_RESUME,
BRCMFMAC_USB_STATE_DOWN,
BRCMFMAC_USB_STATE_DL_FAIL,
BRCMFMAC_USB_STATE_DL_DONE,
BRCMFMAC_USB_STATE_UP,
BRCMFMAC_USB_STATE_SLEEP
};
struct brcmf_stats {

File diff suppressed because it is too large Load Diff

View File

@ -84,31 +84,12 @@ do { \
#define WL_CONN(fmt, args...)
#endif /* (defined DEBUG) */
#define WL_NUM_SCAN_MAX 1
#define WL_NUM_PMKIDS_MAX MAXPMKID /* will be used
* for 2.6.33 kernel
* or later
*/
#define WL_SCAN_BUF_MAX (1024 * 8)
#define WL_NUM_SCAN_MAX 10
#define WL_NUM_PMKIDS_MAX MAXPMKID
#define WL_TLV_INFO_MAX 1024
#define WL_BSS_INFO_MAX 2048
#define WL_ASSOC_INFO_MAX 512 /*
* needs to grab assoc info from dongle to
* report it to cfg80211 through "connect"
* event
*/
#define WL_DCMD_LEN_MAX 1024
#define WL_EXTRA_BUF_MAX 2048
#define WL_ISCAN_BUF_MAX 2048 /*
* the buf length can be BRCMF_DCMD_MAXLEN
* to reduce iteration
*/
#define WL_ISCAN_TIMER_INTERVAL_MS 3000
#define WL_SCAN_ERSULTS_LAST (BRCMF_SCAN_RESULTS_NO_MEM+1)
#define WL_AP_MAX 256 /* virtually unlimitted as long
* as kernel memory allows
*/
#define WL_ASSOC_INFO_MAX 512 /* assoc related fil max buf */
#define WL_EXTRA_BUF_MAX 2048
#define WL_ROAM_TRIGGER_LEVEL -75
#define WL_ROAM_DELTA 20
#define WL_BEACON_TIMEOUT 3
@ -145,12 +126,6 @@ enum wl_mode {
WL_MODE_AP
};
/* dongle iscan state */
enum wl_iscan_state {
WL_ISCAN_STATE_IDLE,
WL_ISCAN_STATE_SCANING
};
/* dongle configuration */
struct brcmf_cfg80211_conf {
u32 mode; /* adhoc , infrastructure or ap */
@ -162,17 +137,6 @@ struct brcmf_cfg80211_conf {
struct ieee80211_channel channel;
};
/* forward declaration */
struct brcmf_cfg80211_info;
/* cfg80211 main event loop */
struct brcmf_cfg80211_event_loop {
s32(*handler[BRCMF_E_LAST]) (struct brcmf_cfg80211_info *cfg,
struct net_device *ndev,
const struct brcmf_event_msg *e,
void *data);
};
/* basic structure of scan request */
struct brcmf_cfg80211_scan_req {
struct brcmf_ssid_le ssid_le;
@ -184,14 +148,6 @@ struct brcmf_cfg80211_ie {
u8 buf[WL_TLV_INFO_MAX];
};
/* event queue for cfg80211 main event */
struct brcmf_cfg80211_event_q {
struct list_head evt_q_list;
u32 etype;
struct brcmf_event_msg emsg;
s8 edata[1];
};
/* security information with currently associated ap */
struct brcmf_cfg80211_security {
u32 wpa_versions;
@ -270,26 +226,6 @@ struct brcmf_cfg80211_vif {
struct list_head list;
};
/* dongle iscan event loop */
struct brcmf_cfg80211_iscan_eloop {
s32 (*handler[WL_SCAN_ERSULTS_LAST])
(struct brcmf_cfg80211_info *cfg);
};
/* dongle iscan controller */
struct brcmf_cfg80211_iscan_ctrl {
struct net_device *ndev;
struct timer_list timer;
u32 timer_ms;
u32 timer_on;
s32 state;
struct work_struct work;
struct brcmf_cfg80211_iscan_eloop el;
void *data;
s8 dcmd_buf[BRCMF_DCMD_SMLEN];
s8 scan_buf[WL_ISCAN_BUF_MAX];
};
/* association inform */
struct brcmf_cfg80211_connect_info {
u8 *req_ie;
@ -323,17 +259,6 @@ struct escan_info {
struct net_device *ndev;
};
/* Structure to hold WPS, WPA IEs for a AP */
struct ap_info {
u8 probe_res_ie[IE_MAX_LEN];
u8 beacon_ie[IE_MAX_LEN];
u32 probe_res_ie_len;
u32 beacon_ie_len;
u8 *wpa_ie;
u8 *rsn_ie;
bool security_mode;
};
/**
* struct brcmf_pno_param_le - PNO scan configuration parameters
*
@ -421,24 +346,16 @@ struct brcmf_pno_scanresults_le {
* @wiphy: wiphy object for cfg80211 interface.
* @conf: dongle configuration.
* @scan_request: cfg80211 scan request object.
* @el: main event loop.
* @evt_q_list: used for event queue.
* @evt_q_lock: for event queue synchronization.
* @usr_sync: mainly for dongle up/down synchronization.
* @bss_list: bss_list holding scanned ap information.
* @scan_results: results of the last scan.
* @scan_req_int: internal scan request object.
* @bss_info: bss information for cfg80211 layer.
* @ie: information element object for internal purpose.
* @iscan: iscan controller information.
* @conn_info: association info.
* @pmk_list: wpa2 pmk list.
* @event_work: event handler work struct.
* @scan_status: scan activity on the dongle.
* @pub: common driver information.
* @channel: current channel.
* @iscan_on: iscan on/off switch.
* @iscan_kickstart: indicate iscan already started.
* @active_scan: current scan mode.
* @sched_escan: e-scan for scheduled scan support running.
* @ibss_starter: indicates this sta is ibss starter.
@ -450,12 +367,10 @@ struct brcmf_pno_scanresults_le {
* @dcmd_buf: dcmd buffer.
* @extra_buf: mainly to grab assoc information.
* @debugfsdir: debugfs folder for this device.
* @escan_on: escan on/off switch.
* @escan_info: escan information.
* @escan_timeout: Timer for catch scan timeout.
* @escan_timeout_work: scan timeout worker.
* @escan_ioctl_buf: dongle command buffer for escan commands.
* @ap_info: host ap information.
* @vif_list: linked list of vif instances.
* @vif_cnt: number of vif instances.
*/
@ -463,24 +378,16 @@ struct brcmf_cfg80211_info {
struct wiphy *wiphy;
struct brcmf_cfg80211_conf *conf;
struct cfg80211_scan_request *scan_request;
struct brcmf_cfg80211_event_loop el;
struct list_head evt_q_list;
spinlock_t evt_q_lock;
struct mutex usr_sync;
struct brcmf_scan_results *bss_list;
struct brcmf_scan_results *scan_results;
struct brcmf_cfg80211_scan_req *scan_req_int;
struct brcmf_cfg80211_scan_req scan_req_int;
struct wl_cfg80211_bss_info *bss_info;
struct brcmf_cfg80211_ie ie;
struct brcmf_cfg80211_iscan_ctrl *iscan;
struct brcmf_cfg80211_connect_info conn_info;
struct brcmf_cfg80211_pmk_list *pmk_list;
struct work_struct event_work;
unsigned long scan_status;
struct brcmf_pub *pub;
u32 channel;
bool iscan_on;
bool iscan_kickstart;
bool active_scan;
bool sched_escan;
bool ibss_starter;
@ -492,12 +399,10 @@ struct brcmf_cfg80211_info {
u8 *dcmd_buf;
u8 *extra_buf;
struct dentry *debugfsdir;
bool escan_on;
struct escan_info escan_info;
struct timer_list escan_timeout;
struct work_struct escan_timeout_work;
u8 *escan_ioctl_buf;
struct ap_info *ap_info;
struct list_head vif_list;
u8 vif_cnt;
};
@ -536,8 +441,11 @@ static inline struct brcmf_cfg80211_profile *ndev_to_prof(struct net_device *nd)
return &ifp->vif->profile;
}
#define iscan_to_cfg(i) ((struct brcmf_cfg80211_info *)(i->data))
#define cfg_to_iscan(w) (w->iscan)
static inline struct brcmf_cfg80211_vif *ndev_to_vif(struct net_device *ndev)
{
struct brcmf_if *ifp = netdev_priv(ndev);
return ifp->vif;
}
static inline struct
brcmf_cfg80211_connect_info *cfg_to_conn(struct brcmf_cfg80211_info *cfg)
@ -547,11 +455,7 @@ brcmf_cfg80211_connect_info *cfg_to_conn(struct brcmf_cfg80211_info *cfg)
struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr);
void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg);
/* event handler from dongle */
void brcmf_cfg80211_event(struct net_device *ndev,
const struct brcmf_event_msg *e, void *data);
s32 brcmf_cfg80211_up(struct brcmf_cfg80211_info *cfg);
s32 brcmf_cfg80211_down(struct brcmf_cfg80211_info *cfg);
s32 brcmf_cfg80211_up(struct net_device *ndev);
s32 brcmf_cfg80211_down(struct net_device *ndev);
#endif /* _wl_cfg80211_h_ */

View File

@ -40,7 +40,8 @@ BRCMSMAC_OFILES := \
phy/phytbl_n.o \
phy/phy_qmath.o \
dma.o \
brcms_trace_events.o
brcms_trace_events.o \
debug.o
MODULEPFX := brcmsmac

View File

@ -21,6 +21,8 @@
#include "antsel.h"
#include "main.h"
#include "ampdu.h"
#include "debug.h"
#include "brcms_trace_events.h"
/* max number of mpdus in an ampdu */
#define AMPDU_MAX_MPDU 32
@ -40,8 +42,6 @@
#define AMPDU_DEF_RETRY_LIMIT 5
/* default tx retry limit at reg rate */
#define AMPDU_DEF_RR_RETRY_LIMIT 2
/* default weight of ampdu in txfifo */
#define AMPDU_DEF_TXPKT_WEIGHT 2
/* default ffpld reserved bytes */
#define AMPDU_DEF_FFPLD_RSVD 2048
/* # of inis to be freed on detach */
@ -114,7 +114,6 @@ struct brcms_fifo_info {
* mpdu_density: min mpdu spacing (0-7) ==> 2^(x-1)/8 usec
* max_pdu: max pdus allowed in ampdu
* dur: max duration of an ampdu (in msec)
* txpkt_weight: weight of ampdu in txfifo; reduces rate lag
* rx_factor: maximum rx ampdu factor (0-3) ==> 2^(13+x) bytes
* ffpld_rsvd: number of bytes to reserve for preload
* max_txlen: max size of ampdu per mcs, bw and sgi
@ -136,7 +135,6 @@ struct ampdu_info {
u8 mpdu_density;
s8 max_pdu;
u8 dur;
u8 txpkt_weight;
u8 rx_factor;
u32 ffpld_rsvd;
u32 max_txlen[MCS_TABLE_SIZE][2][2];
@ -183,18 +181,19 @@ static bool brcms_c_ampdu_cap(struct ampdu_info *ampdu)
static int brcms_c_ampdu_set(struct ampdu_info *ampdu, bool on)
{
struct brcms_c_info *wlc = ampdu->wlc;
struct bcma_device *core = wlc->hw->d11core;
wlc->pub->_ampdu = false;
if (on) {
if (!(wlc->pub->_n_enab & SUPPORT_11N)) {
wiphy_err(ampdu->wlc->wiphy, "wl%d: driver not "
"nmode enabled\n", wlc->pub->unit);
brcms_err(core, "wl%d: driver not nmode enabled\n",
wlc->pub->unit);
return -ENOTSUPP;
}
if (!brcms_c_ampdu_cap(ampdu)) {
wiphy_err(ampdu->wlc->wiphy, "wl%d: device not "
"ampdu capable\n", wlc->pub->unit);
brcms_err(core, "wl%d: device not ampdu capable\n",
wlc->pub->unit);
return -ENOTSUPP;
}
wlc->pub->_ampdu = on;
@ -247,7 +246,6 @@ struct ampdu_info *brcms_c_ampdu_attach(struct brcms_c_info *wlc)
ampdu->mpdu_density = AMPDU_DEF_MPDU_DENSITY;
ampdu->max_pdu = AUTO;
ampdu->dur = AMPDU_MAX_DUR;
ampdu->txpkt_weight = AMPDU_DEF_TXPKT_WEIGHT;
ampdu->ffpld_rsvd = AMPDU_DEF_FFPLD_RSVD;
/*
@ -374,7 +372,8 @@ static int brcms_c_ffpld_check_txfunfl(struct brcms_c_info *wlc, int fid)
offsetof(struct macstat, txfunfl[fid]));
new_txunfl = (u16) (cur_txunfl - fifo->prev_txfunfl);
if (new_txunfl == 0) {
BCMMSG(wlc->wiphy, "TX status FRAG set but no tx underflows\n");
brcms_dbg_ht(wlc->hw->d11core,
"TX status FRAG set but no tx underflows\n");
return -1;
}
fifo->prev_txfunfl = cur_txunfl;
@ -396,8 +395,8 @@ static int brcms_c_ffpld_check_txfunfl(struct brcms_c_info *wlc, int fid)
if (fifo->accum_txfunfl < 10)
return 0;
BCMMSG(wlc->wiphy, "ampdu_count %d tx_underflows %d\n",
current_ampdu_cnt, fifo->accum_txfunfl);
brcms_dbg_ht(wlc->hw->d11core, "ampdu_count %d tx_underflows %d\n",
current_ampdu_cnt, fifo->accum_txfunfl);
/*
compute the current ratio of tx unfl per ampdu.
@ -450,9 +449,10 @@ static int brcms_c_ffpld_check_txfunfl(struct brcms_c_info *wlc, int fid)
(max_mpdu * FFPLD_MPDU_SIZE - fifo->ampdu_pld_size))
/ (max_mpdu * FFPLD_MPDU_SIZE)) * 100;
BCMMSG(wlc->wiphy, "DMA estimated transfer rate %d; "
"pre-load size %d\n",
fifo->dmaxferrate, fifo->ampdu_pld_size);
brcms_dbg_ht(wlc->hw->d11core,
"DMA estimated transfer rate %d; "
"pre-load size %d\n",
fifo->dmaxferrate, fifo->ampdu_pld_size);
} else {
/* decrease ampdu size */
@ -486,7 +486,7 @@ brcms_c_ampdu_tx_operational(struct brcms_c_info *wlc, u8 tid,
scb_ampdu = &scb->scb_ampdu;
if (!ampdu->ini_enable[tid]) {
wiphy_err(ampdu->wlc->wiphy, "%s: Rejecting tid %d\n",
brcms_err(wlc->hw->d11core, "%s: Rejecting tid %d\n",
__func__, tid);
return;
}
@ -498,378 +498,324 @@ brcms_c_ampdu_tx_operational(struct brcms_c_info *wlc, u8 tid,
scb_ampdu->max_rx_ampdu_bytes = max_rx_ampdu_bytes;
}
int
brcms_c_sendampdu(struct ampdu_info *ampdu, struct brcms_txq_info *qi,
struct sk_buff **pdu, int prec)
void brcms_c_ampdu_reset_session(struct brcms_ampdu_session *session,
struct brcms_c_info *wlc)
{
struct brcms_c_info *wlc;
struct sk_buff *p, *pkt[AMPDU_MAX_MPDU];
u8 tid, ndelim;
int err = 0;
session->wlc = wlc;
skb_queue_head_init(&session->skb_list);
session->max_ampdu_len = 0; /* determined from first MPDU */
session->max_ampdu_frames = 0; /* determined from first MPDU */
session->ampdu_len = 0;
session->dma_len = 0;
}
/*
* Preps the given packet for AMPDU based on the session data. If the
* frame cannot be accomodated in the current session, -ENOSPC is
* returned.
*/
int brcms_c_ampdu_add_frame(struct brcms_ampdu_session *session,
struct sk_buff *p)
{
struct brcms_c_info *wlc = session->wlc;
struct ampdu_info *ampdu = wlc->ampdu;
struct scb *scb = &wlc->pri_scb;
struct scb_ampdu *scb_ampdu = &scb->scb_ampdu;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(p);
struct ieee80211_tx_rate *txrate = tx_info->status.rates;
struct d11txh *txh = (struct d11txh *)p->data;
unsigned ampdu_frames;
u8 ndelim, tid;
u8 *plcp;
uint len;
u16 mcl;
bool fbr_iscck;
bool rr;
ndelim = txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM];
plcp = (u8 *)(txh + 1);
fbr_iscck = !(le16_to_cpu(txh->XtraFrameTypes) & 0x03);
len = fbr_iscck ? BRCMS_GET_CCK_PLCP_LEN(txh->FragPLCPFallback) :
BRCMS_GET_MIMO_PLCP_LEN(txh->FragPLCPFallback);
len = roundup(len, 4) + (ndelim + 1) * AMPDU_DELIMITER_LEN;
ampdu_frames = skb_queue_len(&session->skb_list);
if (ampdu_frames != 0) {
struct sk_buff *first;
if (ampdu_frames + 1 > session->max_ampdu_frames ||
session->ampdu_len + len > session->max_ampdu_len)
return -ENOSPC;
/*
* We aren't really out of space if the new frame is of
* a different priority, but we want the same behaviour
* so return -ENOSPC anyway.
*
* XXX: The old AMPDU code did this, but is it really
* necessary?
*/
first = skb_peek(&session->skb_list);
if (p->priority != first->priority)
return -ENOSPC;
}
/*
* Now that we're sure this frame can be accomodated, update the
* session information.
*/
session->ampdu_len += len;
session->dma_len += p->len;
tid = (u8)p->priority;
/* Handle retry limits */
if (txrate[0].count <= ampdu->rr_retry_limit_tid[tid]) {
txrate[0].count++;
rr = true;
} else {
txrate[1].count++;
rr = false;
}
if (ampdu_frames == 0) {
u8 plcp0, plcp3, is40, sgi, mcs;
uint fifo = le16_to_cpu(txh->TxFrameID) & TXFID_QUEUE_MASK;
struct brcms_fifo_info *f = &ampdu->fifo_tb[fifo];
if (rr) {
plcp0 = plcp[0];
plcp3 = plcp[3];
} else {
plcp0 = txh->FragPLCPFallback[0];
plcp3 = txh->FragPLCPFallback[3];
}
/* Limit AMPDU size based on MCS */
is40 = (plcp0 & MIMO_PLCP_40MHZ) ? 1 : 0;
sgi = plcp3_issgi(plcp3) ? 1 : 0;
mcs = plcp0 & ~MIMO_PLCP_40MHZ;
session->max_ampdu_len = min(scb_ampdu->max_rx_ampdu_bytes,
ampdu->max_txlen[mcs][is40][sgi]);
session->max_ampdu_frames = scb_ampdu->max_pdu;
if (mcs_2_rate(mcs, true, false) >= f->dmaxferrate) {
session->max_ampdu_frames =
min_t(u16, f->mcs2ampdu_table[mcs],
session->max_ampdu_frames);
}
}
/*
* Treat all frames as "middle" frames of AMPDU here. First and
* last frames must be fixed up after all MPDUs have been prepped.
*/
mcl = le16_to_cpu(txh->MacTxControlLow);
mcl &= ~TXC_AMPDU_MASK;
mcl |= (TXC_AMPDU_MIDDLE << TXC_AMPDU_SHIFT);
mcl &= ~(TXC_STARTMSDU | TXC_SENDRTS | TXC_SENDCTS);
txh->MacTxControlLow = cpu_to_le16(mcl);
txh->PreloadSize = 0; /* always default to 0 */
skb_queue_tail(&session->skb_list, p);
return 0;
}
void brcms_c_ampdu_finalize(struct brcms_ampdu_session *session)
{
struct brcms_c_info *wlc = session->wlc;
struct ampdu_info *ampdu = wlc->ampdu;
struct sk_buff *first, *last;
struct d11txh *txh;
struct ieee80211_tx_info *tx_info;
struct ieee80211_tx_rate *txrate;
u8 ndelim;
u8 *plcp;
uint len;
uint fifo;
struct brcms_fifo_info *f;
u16 mcl;
bool fbr;
bool fbr_iscck;
struct ieee80211_rts *rts;
bool use_rts = false, use_cts = false;
u16 dma_len = session->dma_len;
u16 mimo_ctlchbw = PHY_TXC1_BW_20MHZ;
u32 rspec = 0, rspec_fallback = 0;
u32 rts_rspec = 0, rts_rspec_fallback = 0;
u8 plcp0, plcp3, is40, sgi, mcs;
u16 mch;
u8 preamble_type = BRCMS_GF_PREAMBLE;
u8 fbr_preamble_type = BRCMS_GF_PREAMBLE;
u8 rts_preamble_type = BRCMS_LONG_PREAMBLE;
u8 rts_fbr_preamble_type = BRCMS_LONG_PREAMBLE;
bool rr = true, fbr = false;
uint i, count = 0, fifo, seg_cnt = 0;
u16 plen, len, seq = 0, mcl, mch, index, frameid, dma_len = 0;
u32 ampdu_len, max_ampdu_bytes = 0;
struct d11txh *txh = NULL;
u8 *plcp;
struct ieee80211_hdr *h;
struct scb *scb;
struct scb_ampdu *scb_ampdu;
struct scb_ampdu_tid_ini *ini;
u8 mcs = 0;
bool use_rts = false, use_cts = false;
u32 rspec = 0, rspec_fallback = 0;
u32 rts_rspec = 0, rts_rspec_fallback = 0;
u16 mimo_ctlchbw = PHY_TXC1_BW_20MHZ;
struct ieee80211_rts *rts;
u8 rr_retry_limit;
struct brcms_fifo_info *f;
bool fbr_iscck;
struct ieee80211_tx_info *tx_info;
u16 qlen;
struct wiphy *wiphy;
if (skb_queue_empty(&session->skb_list))
return;
wlc = ampdu->wlc;
wiphy = wlc->wiphy;
p = *pdu;
first = skb_peek(&session->skb_list);
last = skb_peek_tail(&session->skb_list);
tid = (u8) (p->priority);
/* Need to fix up last MPDU first to adjust AMPDU length */
txh = (struct d11txh *)last->data;
fifo = le16_to_cpu(txh->TxFrameID) & TXFID_QUEUE_MASK;
f = &ampdu->fifo_tb[fifo];
f = ampdu->fifo_tb + prio2fifo[tid];
mcl = le16_to_cpu(txh->MacTxControlLow);
mcl &= ~TXC_AMPDU_MASK;
mcl |= (TXC_AMPDU_LAST << TXC_AMPDU_SHIFT);
txh->MacTxControlLow = cpu_to_le16(mcl);
scb = &wlc->pri_scb;
scb_ampdu = &scb->scb_ampdu;
ini = &scb_ampdu->ini[tid];
/* remove the null delimiter after last mpdu */
ndelim = txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM];
txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM] = 0;
session->ampdu_len -= ndelim * AMPDU_DELIMITER_LEN;
/* Let pressure continue to build ... */
qlen = pktq_plen(&qi->q, prec);
if (ini->tx_in_transit > 0 &&
qlen < min(scb_ampdu->max_pdu, ini->ba_wsize))
/* Collect multiple MPDU's to be sent in the next AMPDU */
return -EBUSY;
/* remove the pad len from last mpdu */
fbr_iscck = ((le16_to_cpu(txh->XtraFrameTypes) & 0x3) == 0);
len = fbr_iscck ? BRCMS_GET_CCK_PLCP_LEN(txh->FragPLCPFallback) :
BRCMS_GET_MIMO_PLCP_LEN(txh->FragPLCPFallback);
session->ampdu_len -= roundup(len, 4) - len;
/* at this point we intend to transmit an AMPDU */
rr_retry_limit = ampdu->rr_retry_limit_tid[tid];
ampdu_len = 0;
dma_len = 0;
while (p) {
struct ieee80211_tx_rate *txrate;
/* Now fix up the first MPDU */
tx_info = IEEE80211_SKB_CB(first);
txrate = tx_info->status.rates;
txh = (struct d11txh *)first->data;
plcp = (u8 *)(txh + 1);
rts = (struct ieee80211_rts *)&txh->rts_frame;
tx_info = IEEE80211_SKB_CB(p);
txrate = tx_info->status.rates;
if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
err = brcms_c_prep_pdu(wlc, p, &fifo);
} else {
wiphy_err(wiphy, "%s: AMPDU flag is off!\n", __func__);
*pdu = NULL;
err = 0;
break;
}
if (err) {
if (err == -EBUSY) {
wiphy_err(wiphy, "wl%d: sendampdu: "
"prep_xdu retry; seq 0x%x\n",
wlc->pub->unit, seq);
*pdu = p;
break;
}
/* error in the packet; reject it */
wiphy_err(wiphy, "wl%d: sendampdu: prep_xdu "
"rejected; seq 0x%x\n", wlc->pub->unit, seq);
*pdu = NULL;
break;
}
/* pkt is good to be aggregated */
txh = (struct d11txh *) p->data;
plcp = (u8 *) (txh + 1);
h = (struct ieee80211_hdr *)(plcp + D11_PHY_HDR_LEN);
seq = le16_to_cpu(h->seq_ctrl) >> SEQNUM_SHIFT;
index = TX_SEQ_TO_INDEX(seq);
/* check mcl fields and test whether it can be agg'd */
mcl = le16_to_cpu(txh->MacTxControlLow);
mcl = le16_to_cpu(txh->MacTxControlLow);
/* If only one MPDU leave it marked as last */
if (first != last) {
mcl &= ~TXC_AMPDU_MASK;
fbr_iscck = !(le16_to_cpu(txh->XtraFrameTypes) & 0x3);
txh->PreloadSize = 0; /* always default to 0 */
/* Handle retry limits */
if (txrate[0].count <= rr_retry_limit) {
txrate[0].count++;
rr = true;
fbr = false;
} else {
fbr = true;
rr = false;
txrate[1].count++;
}
/* extract the length info */
len = fbr_iscck ? BRCMS_GET_CCK_PLCP_LEN(txh->FragPLCPFallback)
: BRCMS_GET_MIMO_PLCP_LEN(txh->FragPLCPFallback);
/* retrieve null delimiter count */
ndelim = txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM];
seg_cnt += 1;
BCMMSG(wlc->wiphy, "wl%d: mpdu %d plcp_len %d\n",
wlc->pub->unit, count, len);
/*
* aggregateable mpdu. For ucode/hw agg,
* test whether need to break or change the epoch
*/
if (count == 0) {
mcl |= (TXC_AMPDU_FIRST << TXC_AMPDU_SHIFT);
/* refill the bits since might be a retx mpdu */
mcl |= TXC_STARTMSDU;
rts = (struct ieee80211_rts *)&txh->rts_frame;
if (ieee80211_is_rts(rts->frame_control)) {
mcl |= TXC_SENDRTS;
use_rts = true;
}
if (ieee80211_is_cts(rts->frame_control)) {
mcl |= TXC_SENDCTS;
use_cts = true;
}
} else {
mcl |= (TXC_AMPDU_MIDDLE << TXC_AMPDU_SHIFT);
mcl &= ~(TXC_STARTMSDU | TXC_SENDRTS | TXC_SENDCTS);
}
len = roundup(len, 4);
ampdu_len += (len + (ndelim + 1) * AMPDU_DELIMITER_LEN);
dma_len += (u16) p->len;
BCMMSG(wlc->wiphy, "wl%d: ampdu_len %d"
" seg_cnt %d null delim %d\n",
wlc->pub->unit, ampdu_len, seg_cnt, ndelim);
txh->MacTxControlLow = cpu_to_le16(mcl);
/* this packet is added */
pkt[count++] = p;
/* patch the first MPDU */
if (count == 1) {
u8 plcp0, plcp3, is40, sgi;
if (rr) {
plcp0 = plcp[0];
plcp3 = plcp[3];
} else {
plcp0 = txh->FragPLCPFallback[0];
plcp3 = txh->FragPLCPFallback[3];
}
is40 = (plcp0 & MIMO_PLCP_40MHZ) ? 1 : 0;
sgi = plcp3_issgi(plcp3) ? 1 : 0;
mcs = plcp0 & ~MIMO_PLCP_40MHZ;
max_ampdu_bytes =
min(scb_ampdu->max_rx_ampdu_bytes,
ampdu->max_txlen[mcs][is40][sgi]);
if (is40)
mimo_ctlchbw =
CHSPEC_SB_UPPER(wlc_phy_chanspec_get(
wlc->band->pi))
? PHY_TXC1_BW_20MHZ_UP : PHY_TXC1_BW_20MHZ;
/* rebuild the rspec and rspec_fallback */
rspec = RSPEC_MIMORATE;
rspec |= plcp[0] & ~MIMO_PLCP_40MHZ;
if (plcp[0] & MIMO_PLCP_40MHZ)
rspec |= (PHY_TXC1_BW_40MHZ << RSPEC_BW_SHIFT);
if (fbr_iscck) /* CCK */
rspec_fallback = cck_rspec(cck_phy2mac_rate
(txh->FragPLCPFallback[0]));
else { /* MIMO */
rspec_fallback = RSPEC_MIMORATE;
rspec_fallback |=
txh->FragPLCPFallback[0] & ~MIMO_PLCP_40MHZ;
if (txh->FragPLCPFallback[0] & MIMO_PLCP_40MHZ)
rspec_fallback |=
(PHY_TXC1_BW_40MHZ <<
RSPEC_BW_SHIFT);
}
if (use_rts || use_cts) {
rts_rspec =
brcms_c_rspec_to_rts_rspec(wlc,
rspec, false, mimo_ctlchbw);
rts_rspec_fallback =
brcms_c_rspec_to_rts_rspec(wlc,
rspec_fallback, false, mimo_ctlchbw);
}
}
/* if (first mpdu for host agg) */
/* test whether to add more */
if ((mcs_2_rate(mcs, true, false) >= f->dmaxferrate) &&
(count == f->mcs2ampdu_table[mcs])) {
BCMMSG(wlc->wiphy, "wl%d: PR 37644: stopping"
" ampdu at %d for mcs %d\n",
wlc->pub->unit, count, mcs);
break;
}
if (count == scb_ampdu->max_pdu)
break;
/*
* check to see if the next pkt is
* a candidate for aggregation
*/
p = pktq_ppeek(&qi->q, prec);
if (p) {
tx_info = IEEE80211_SKB_CB(p);
if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) &&
((u8) (p->priority) == tid)) {
plen = p->len + AMPDU_MAX_MPDU_OVERHEAD;
plen = max(scb_ampdu->min_len, plen);
if ((plen + ampdu_len) > max_ampdu_bytes) {
p = NULL;
continue;
}
/*
* check if there are enough
* descriptors available
*/
if (*wlc->core->txavail[fifo] <= seg_cnt + 1) {
wiphy_err(wiphy, "%s: No fifo space "
"!!\n", __func__);
p = NULL;
continue;
}
/* next packet fit for aggregation so dequeue */
p = brcmu_pktq_pdeq(&qi->q, prec);
} else {
p = NULL;
}
}
} /* end while(p) */
ini->tx_in_transit += count;
if (count) {
/* patch up the last txh */
txh = (struct d11txh *) pkt[count - 1]->data;
mcl = le16_to_cpu(txh->MacTxControlLow);
mcl &= ~TXC_AMPDU_MASK;
mcl |= (TXC_AMPDU_LAST << TXC_AMPDU_SHIFT);
txh->MacTxControlLow = cpu_to_le16(mcl);
/* remove the null delimiter after last mpdu */
ndelim = txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM];
txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM] = 0;
ampdu_len -= ndelim * AMPDU_DELIMITER_LEN;
/* remove the pad len from last mpdu */
fbr_iscck = ((le16_to_cpu(txh->XtraFrameTypes) & 0x3) == 0);
len = fbr_iscck ? BRCMS_GET_CCK_PLCP_LEN(txh->FragPLCPFallback)
: BRCMS_GET_MIMO_PLCP_LEN(txh->FragPLCPFallback);
ampdu_len -= roundup(len, 4) - len;
/* patch up the first txh & plcp */
txh = (struct d11txh *) pkt[0]->data;
plcp = (u8 *) (txh + 1);
BRCMS_SET_MIMO_PLCP_LEN(plcp, ampdu_len);
/* mark plcp to indicate ampdu */
BRCMS_SET_MIMO_PLCP_AMPDU(plcp);
/* reset the mixed mode header durations */
if (txh->MModeLen) {
u16 mmodelen =
brcms_c_calc_lsig_len(wlc, rspec, ampdu_len);
txh->MModeLen = cpu_to_le16(mmodelen);
preamble_type = BRCMS_MM_PREAMBLE;
}
if (txh->MModeFbrLen) {
u16 mmfbrlen =
brcms_c_calc_lsig_len(wlc, rspec_fallback,
ampdu_len);
txh->MModeFbrLen = cpu_to_le16(mmfbrlen);
fbr_preamble_type = BRCMS_MM_PREAMBLE;
}
/* set the preload length */
if (mcs_2_rate(mcs, true, false) >= f->dmaxferrate) {
dma_len = min(dma_len, f->ampdu_pld_size);
txh->PreloadSize = cpu_to_le16(dma_len);
} else
txh->PreloadSize = 0;
mch = le16_to_cpu(txh->MacTxControlHigh);
/* update RTS dur fields */
if (use_rts || use_cts) {
u16 durid;
rts = (struct ieee80211_rts *)&txh->rts_frame;
if ((mch & TXC_PREAMBLE_RTS_MAIN_SHORT) ==
TXC_PREAMBLE_RTS_MAIN_SHORT)
rts_preamble_type = BRCMS_SHORT_PREAMBLE;
if ((mch & TXC_PREAMBLE_RTS_FB_SHORT) ==
TXC_PREAMBLE_RTS_FB_SHORT)
rts_fbr_preamble_type = BRCMS_SHORT_PREAMBLE;
durid =
brcms_c_compute_rtscts_dur(wlc, use_cts, rts_rspec,
rspec, rts_preamble_type,
preamble_type, ampdu_len,
true);
rts->duration = cpu_to_le16(durid);
durid = brcms_c_compute_rtscts_dur(wlc, use_cts,
rts_rspec_fallback,
rspec_fallback,
rts_fbr_preamble_type,
fbr_preamble_type,
ampdu_len, true);
txh->RTSDurFallback = cpu_to_le16(durid);
/* set TxFesTimeNormal */
txh->TxFesTimeNormal = rts->duration;
/* set fallback rate version of TxFesTimeNormal */
txh->TxFesTimeFallback = txh->RTSDurFallback;
}
/* set flag and plcp for fallback rate */
if (fbr) {
mch |= TXC_AMPDU_FBR;
txh->MacTxControlHigh = cpu_to_le16(mch);
BRCMS_SET_MIMO_PLCP_AMPDU(plcp);
BRCMS_SET_MIMO_PLCP_AMPDU(txh->FragPLCPFallback);
}
BCMMSG(wlc->wiphy, "wl%d: count %d ampdu_len %d\n",
wlc->pub->unit, count, ampdu_len);
/* inform rate_sel if it this is a rate probe pkt */
frameid = le16_to_cpu(txh->TxFrameID);
if (frameid & TXFID_RATE_PROBE_MASK)
wiphy_err(wiphy, "%s: XXX what to do with "
"TXFID_RATE_PROBE_MASK!?\n", __func__);
for (i = 0; i < count; i++)
brcms_c_txfifo(wlc, fifo, pkt[i], i == (count - 1),
ampdu->txpkt_weight);
mcl |= (TXC_AMPDU_FIRST << TXC_AMPDU_SHIFT);
}
/* endif (count) */
return err;
mcl |= TXC_STARTMSDU;
if (ieee80211_is_rts(rts->frame_control)) {
mcl |= TXC_SENDRTS;
use_rts = true;
}
if (ieee80211_is_cts(rts->frame_control)) {
mcl |= TXC_SENDCTS;
use_cts = true;
}
txh->MacTxControlLow = cpu_to_le16(mcl);
fbr = txrate[1].count > 0;
if (!fbr) {
plcp0 = plcp[0];
plcp3 = plcp[3];
} else {
plcp0 = txh->FragPLCPFallback[0];
plcp3 = txh->FragPLCPFallback[3];
}
is40 = (plcp0 & MIMO_PLCP_40MHZ) ? 1 : 0;
sgi = plcp3_issgi(plcp3) ? 1 : 0;
mcs = plcp0 & ~MIMO_PLCP_40MHZ;
if (is40) {
if (CHSPEC_SB_UPPER(wlc_phy_chanspec_get(wlc->band->pi)))
mimo_ctlchbw = PHY_TXC1_BW_20MHZ_UP;
else
mimo_ctlchbw = PHY_TXC1_BW_20MHZ;
}
/* rebuild the rspec and rspec_fallback */
rspec = RSPEC_MIMORATE;
rspec |= plcp[0] & ~MIMO_PLCP_40MHZ;
if (plcp[0] & MIMO_PLCP_40MHZ)
rspec |= (PHY_TXC1_BW_40MHZ << RSPEC_BW_SHIFT);
fbr_iscck = !(le16_to_cpu(txh->XtraFrameTypes) & 0x03);
if (fbr_iscck) {
rspec_fallback =
cck_rspec(cck_phy2mac_rate(txh->FragPLCPFallback[0]));
} else {
rspec_fallback = RSPEC_MIMORATE;
rspec_fallback |= txh->FragPLCPFallback[0] & ~MIMO_PLCP_40MHZ;
if (txh->FragPLCPFallback[0] & MIMO_PLCP_40MHZ)
rspec_fallback |= PHY_TXC1_BW_40MHZ << RSPEC_BW_SHIFT;
}
if (use_rts || use_cts) {
rts_rspec =
brcms_c_rspec_to_rts_rspec(wlc, rspec,
false, mimo_ctlchbw);
rts_rspec_fallback =
brcms_c_rspec_to_rts_rspec(wlc, rspec_fallback,
false, mimo_ctlchbw);
}
BRCMS_SET_MIMO_PLCP_LEN(plcp, session->ampdu_len);
/* mark plcp to indicate ampdu */
BRCMS_SET_MIMO_PLCP_AMPDU(plcp);
/* reset the mixed mode header durations */
if (txh->MModeLen) {
u16 mmodelen = brcms_c_calc_lsig_len(wlc, rspec,
session->ampdu_len);
txh->MModeLen = cpu_to_le16(mmodelen);
preamble_type = BRCMS_MM_PREAMBLE;
}
if (txh->MModeFbrLen) {
u16 mmfbrlen = brcms_c_calc_lsig_len(wlc, rspec_fallback,
session->ampdu_len);
txh->MModeFbrLen = cpu_to_le16(mmfbrlen);
fbr_preamble_type = BRCMS_MM_PREAMBLE;
}
/* set the preload length */
if (mcs_2_rate(mcs, true, false) >= f->dmaxferrate) {
dma_len = min(dma_len, f->ampdu_pld_size);
txh->PreloadSize = cpu_to_le16(dma_len);
} else {
txh->PreloadSize = 0;
}
mch = le16_to_cpu(txh->MacTxControlHigh);
/* update RTS dur fields */
if (use_rts || use_cts) {
u16 durid;
if ((mch & TXC_PREAMBLE_RTS_MAIN_SHORT) ==
TXC_PREAMBLE_RTS_MAIN_SHORT)
rts_preamble_type = BRCMS_SHORT_PREAMBLE;
if ((mch & TXC_PREAMBLE_RTS_FB_SHORT) ==
TXC_PREAMBLE_RTS_FB_SHORT)
rts_fbr_preamble_type = BRCMS_SHORT_PREAMBLE;
durid = brcms_c_compute_rtscts_dur(wlc, use_cts, rts_rspec,
rspec, rts_preamble_type,
preamble_type,
session->ampdu_len, true);
rts->duration = cpu_to_le16(durid);
durid = brcms_c_compute_rtscts_dur(wlc, use_cts,
rts_rspec_fallback,
rspec_fallback,
rts_fbr_preamble_type,
fbr_preamble_type,
session->ampdu_len, true);
txh->RTSDurFallback = cpu_to_le16(durid);
/* set TxFesTimeNormal */
txh->TxFesTimeNormal = rts->duration;
/* set fallback rate version of TxFesTimeNormal */
txh->TxFesTimeFallback = txh->RTSDurFallback;
}
/* set flag and plcp for fallback rate */
if (fbr) {
mch |= TXC_AMPDU_FBR;
txh->MacTxControlHigh = cpu_to_le16(mch);
BRCMS_SET_MIMO_PLCP_AMPDU(plcp);
BRCMS_SET_MIMO_PLCP_AMPDU(txh->FragPLCPFallback);
}
brcms_dbg_ht(wlc->hw->d11core, "wl%d: count %d ampdu_len %d\n",
wlc->pub->unit, skb_queue_len(&session->skb_list),
session->ampdu_len);
}
static void
@ -909,7 +855,6 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
u8 antselid = 0;
u8 retry_limit, rr_retry_limit;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(p);
struct wiphy *wiphy = wlc->wiphy;
#ifdef DEBUG
u8 hole[AMPDU_MAX_MPDU];
@ -955,13 +900,14 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
if (supr_status) {
update_rate = false;
if (supr_status == TX_STATUS_SUPR_BADCH) {
wiphy_err(wiphy,
brcms_err(wlc->hw->d11core,
"%s: Pkt tx suppressed, illegal channel possibly %d\n",
__func__, CHSPEC_CHANNEL(
wlc->default_bss->chanspec));
} else {
if (supr_status != TX_STATUS_SUPR_FRAG)
wiphy_err(wiphy, "%s: supr_status 0x%x\n",
brcms_err(wlc->hw->d11core,
"%s: supr_status 0x%x\n",
__func__, supr_status);
}
/* no need to retry for badch; will fail again */
@ -977,20 +923,14 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
* if there were underflows, but pre-loading
* is not active, notify rate adaptation.
*/
if (brcms_c_ffpld_check_txfunfl(wlc,
prio2fifo[tid]) > 0)
if (brcms_c_ffpld_check_txfunfl(wlc, queue) > 0)
tx_error = true;
}
} else if (txs->phyerr) {
update_rate = false;
wiphy_err(wiphy, "%s: ampdu tx phy error (0x%x)\n",
brcms_err(wlc->hw->d11core,
"%s: ampdu tx phy error (0x%x)\n",
__func__, txs->phyerr);
if (brcm_msg_level & LOG_ERROR_VAL) {
brcmu_prpkt("txpkt (AMPDU)", p);
brcms_c_print_txdesc((struct d11txh *) p->data);
}
brcms_c_print_txstatus(txs);
}
}
@ -1003,6 +943,8 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
h = (struct ieee80211_hdr *)(plcp + D11_PHY_HDR_LEN);
seq = le16_to_cpu(h->seq_ctrl) >> SEQNUM_SHIFT;
trace_brcms_txdesc(&wlc->hw->d11core->dev, txh, sizeof(*txh));
if (tot_mpdu == 0) {
mcs = plcp[0] & MIMO_PLCP_MCS_MASK;
mimoantsel = le16_to_cpu(txh->ABI_MimoAntSel);
@ -1012,10 +954,10 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
ack_recd = false;
if (ba_recd) {
bindex = MODSUB_POW2(seq, start_seq, SEQNUM_MAX);
BCMMSG(wiphy,
"tid %d seq %d, start_seq %d, bindex %d set %d, index %d\n",
tid, seq, start_seq, bindex,
isset(bitmap, bindex), index);
brcms_dbg_ht(wlc->hw->d11core,
"tid %d seq %d, start_seq %d, bindex %d set %d, index %d\n",
tid, seq, start_seq, bindex,
isset(bitmap, bindex), index);
/* if acked then clear bit and free packet */
if ((bindex < AMPDU_TX_BA_MAX_WSIZE)
&& isset(bitmap, bindex)) {
@ -1046,14 +988,16 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
/* either retransmit or send bar if ack not recd */
if (!ack_recd) {
if (retry && (ini->txretry[index] < (int)retry_limit)) {
int ret;
ini->txretry[index]++;
ini->tx_in_transit--;
ret = brcms_c_txfifo(wlc, queue, p);
/*
* Use high prededence for retransmit to
* give some punch
* We shouldn't be out of space in the DMA
* ring here since we're reinserting a frame
* that was just pulled out.
*/
brcms_c_txq_enq(wlc, scb, p,
BRCMS_PRIO_TO_HI_PREC(tid));
WARN_ONCE(ret, "queue %d out of txds\n", queue);
} else {
/* Retry timeout */
ini->tx_in_transit--;
@ -1064,9 +1008,9 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
IEEE80211_TX_STAT_AMPDU_NO_BACK;
skb_pull(p, D11_PHY_HDR_LEN);
skb_pull(p, D11_TXH_LEN);
BCMMSG(wiphy,
"BA Timeout, seq %d, in_transit %d\n",
seq, ini->tx_in_transit);
brcms_dbg_ht(wlc->hw->d11core,
"BA Timeout, seq %d, in_transit %d\n",
seq, ini->tx_in_transit);
ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw,
p);
}
@ -1080,12 +1024,9 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
p = dma_getnexttxp(wlc->hw->di[queue], DMA_RANGE_TRANSMITTED);
}
brcms_c_send_q(wlc);
/* update rate state */
antselid = brcms_c_antsel_antsel2id(wlc->asi, mimoantsel);
brcms_c_txfifo_complete(wlc, queue, ampdu->txpkt_weight);
}
void
@ -1133,6 +1074,8 @@ brcms_c_ampdu_dotxstatus(struct ampdu_info *ampdu, struct scb *scb,
while (p) {
tx_info = IEEE80211_SKB_CB(p);
txh = (struct d11txh *) p->data;
trace_brcms_txdesc(&wlc->hw->d11core->dev, txh,
sizeof(*txh));
mcl = le16_to_cpu(txh->MacTxControlLow);
brcmu_pkt_buf_free_skb(p);
/* break out if last packet of ampdu */
@ -1142,7 +1085,6 @@ brcms_c_ampdu_dotxstatus(struct ampdu_info *ampdu, struct scb *scb,
p = dma_getnexttxp(wlc->hw->di[queue],
DMA_RANGE_TRANSMITTED);
}
brcms_c_txfifo_complete(wlc, queue, ampdu->txpkt_weight);
}
}
@ -1181,23 +1123,6 @@ void brcms_c_ampdu_shm_upd(struct ampdu_info *ampdu)
}
}
/*
* callback function that helps flushing ampdu packets from a priority queue
*/
static bool cb_del_ampdu_pkt(struct sk_buff *mpdu, void *arg_a)
{
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(mpdu);
struct cb_del_ampdu_pars *ampdu_pars =
(struct cb_del_ampdu_pars *)arg_a;
bool rc;
rc = tx_info->flags & IEEE80211_TX_CTL_AMPDU ? true : false;
rc = rc && (tx_info->rate_driver_data[0] == NULL || ampdu_pars->sta == NULL ||
tx_info->rate_driver_data[0] == ampdu_pars->sta);
rc = rc && ((u8)(mpdu->priority) == ampdu_pars->tid);
return rc;
}
/*
* callback function that helps invalidating ampdu packets in a DMA queue
*/
@ -1218,15 +1143,5 @@ static void dma_cb_fn_ampdu(void *txi, void *arg_a)
void brcms_c_ampdu_flush(struct brcms_c_info *wlc,
struct ieee80211_sta *sta, u16 tid)
{
struct brcms_txq_info *qi = wlc->pkt_queue;
struct pktq *pq = &qi->q;
int prec;
struct cb_del_ampdu_pars ampdu_pars;
ampdu_pars.sta = sta;
ampdu_pars.tid = tid;
for (prec = 0; prec < pq->num_prec; prec++)
brcmu_pktq_pflush(pq, prec, true, cb_del_ampdu_pkt,
(void *)&ampdu_pars);
brcms_c_inval_dma_pkts(wlc->hw, sta, dma_cb_fn_ampdu);
}

View File

@ -17,11 +17,34 @@
#ifndef _BRCM_AMPDU_H_
#define _BRCM_AMPDU_H_
/*
* Data structure representing an in-progress session for accumulating
* frames for AMPDU.
*
* wlc: pointer to common driver data
* skb_list: queue of skb's for AMPDU
* max_ampdu_len: maximum length for this AMPDU
* max_ampdu_frames: maximum number of frames for this AMPDU
* ampdu_len: total number of bytes accumulated for this AMPDU
* dma_len: DMA length of this AMPDU
*/
struct brcms_ampdu_session {
struct brcms_c_info *wlc;
struct sk_buff_head skb_list;
unsigned max_ampdu_len;
u16 max_ampdu_frames;
u16 ampdu_len;
u16 dma_len;
};
extern void brcms_c_ampdu_reset_session(struct brcms_ampdu_session *session,
struct brcms_c_info *wlc);
extern int brcms_c_ampdu_add_frame(struct brcms_ampdu_session *session,
struct sk_buff *p);
extern void brcms_c_ampdu_finalize(struct brcms_ampdu_session *session);
extern struct ampdu_info *brcms_c_ampdu_attach(struct brcms_c_info *wlc);
extern void brcms_c_ampdu_detach(struct ampdu_info *ampdu);
extern int brcms_c_sendampdu(struct ampdu_info *ampdu,
struct brcms_txq_info *qi,
struct sk_buff **aggp, int prec);
extern void brcms_c_ampdu_dotxstatus(struct ampdu_info *ampdu, struct scb *scb,
struct sk_buff *p, struct tx_status *txs);
extern void brcms_c_ampdu_macaddr_upd(struct brcms_c_info *wlc);

View File

@ -21,6 +21,7 @@
#include "main.h"
#include "phy_shim.h"
#include "antsel.h"
#include "debug.h"
#define ANT_SELCFG_AUTO 0x80 /* bit indicates antenna sel AUTO */
#define ANT_SELCFG_MASK 0x33 /* antenna configuration mask */
@ -137,7 +138,8 @@ struct antsel_info *brcms_c_antsel_attach(struct brcms_c_info *wlc)
asi->antsel_avail = false;
} else {
asi->antsel_avail = false;
wiphy_err(wlc->wiphy, "antsel_attach: 2o3 "
brcms_err(wlc->hw->d11core,
"antsel_attach: 2o3 "
"board cfg invalid\n");
}

View File

@ -14,22 +14,29 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#undef TRACE_SYSTEM
#define TRACE_SYSTEM brcmsmac
#if !defined(__TRACE_BRCMSMAC_H) || defined(TRACE_HEADER_MULTI_READ)
#define __TRACE_BRCMSMAC_H
#include <linux/types.h>
#include <linux/device.h>
#include <linux/tracepoint.h>
#include "mac80211_if.h"
#ifndef CONFIG_BRCMDBG
#ifndef CONFIG_BRCM_TRACING
#undef TRACE_EVENT
#define TRACE_EVENT(name, proto, ...) \
static inline void trace_ ## name(proto) {}
#undef DECLARE_EVENT_CLASS
#define DECLARE_EVENT_CLASS(...)
#undef DEFINE_EVENT
#define DEFINE_EVENT(evt_class, name, proto, ...) \
static inline void trace_ ## name(proto) {}
#endif
#undef TRACE_SYSTEM
#define TRACE_SYSTEM brcmsmac
/*
* We define a tracepoint, its arguments, its printk format and its
* 'fast binary record' layout.
@ -78,9 +85,165 @@ TRACE_EVENT(brcms_dpc,
)
);
TRACE_EVENT(brcms_macintstatus,
TP_PROTO(const struct device *dev, int in_isr, u32 macintstatus,
u32 mask),
TP_ARGS(dev, in_isr, macintstatus, mask),
TP_STRUCT__entry(
__string(dev, dev_name(dev))
__field(int, in_isr)
__field(u32, macintstatus)
__field(u32, mask)
),
TP_fast_assign(
__assign_str(dev, dev_name(dev));
__entry->in_isr = in_isr;
__entry->macintstatus = macintstatus;
__entry->mask = mask;
),
TP_printk("[%s] in_isr=%d macintstatus=%#x mask=%#x", __get_str(dev),
__entry->in_isr, __entry->macintstatus, __entry->mask)
);
#undef TRACE_SYSTEM
#define TRACE_SYSTEM brcmsmac_tx
TRACE_EVENT(brcms_txdesc,
TP_PROTO(const struct device *dev,
void *txh, size_t txh_len),
TP_ARGS(dev, txh, txh_len),
TP_STRUCT__entry(
__string(dev, dev_name(dev))
__dynamic_array(u8, txh, txh_len)
),
TP_fast_assign(
__assign_str(dev, dev_name(dev));
memcpy(__get_dynamic_array(txh), txh, txh_len);
),
TP_printk("[%s] txdesc", __get_str(dev))
);
TRACE_EVENT(brcms_txstatus,
TP_PROTO(const struct device *dev, u16 framelen, u16 frameid,
u16 status, u16 lasttxtime, u16 sequence, u16 phyerr,
u16 ackphyrxsh),
TP_ARGS(dev, framelen, frameid, status, lasttxtime, sequence, phyerr,
ackphyrxsh),
TP_STRUCT__entry(
__string(dev, dev_name(dev))
__field(u16, framelen)
__field(u16, frameid)
__field(u16, status)
__field(u16, lasttxtime)
__field(u16, sequence)
__field(u16, phyerr)
__field(u16, ackphyrxsh)
),
TP_fast_assign(
__assign_str(dev, dev_name(dev));
__entry->framelen = framelen;
__entry->frameid = frameid;
__entry->status = status;
__entry->lasttxtime = lasttxtime;
__entry->sequence = sequence;
__entry->phyerr = phyerr;
__entry->ackphyrxsh = ackphyrxsh;
),
TP_printk("[%s] FrameId %#04x TxStatus %#04x LastTxTime %#04x "
"Seq %#04x PHYTxStatus %#04x RxAck %#04x",
__get_str(dev), __entry->frameid, __entry->status,
__entry->lasttxtime, __entry->sequence, __entry->phyerr,
__entry->ackphyrxsh)
);
TRACE_EVENT(brcms_ampdu_session,
TP_PROTO(const struct device *dev, unsigned max_ampdu_len,
u16 max_ampdu_frames, u16 ampdu_len, u16 ampdu_frames,
u16 dma_len),
TP_ARGS(dev, max_ampdu_len, max_ampdu_frames, ampdu_len, ampdu_frames,
dma_len),
TP_STRUCT__entry(
__string(dev, dev_name(dev))
__field(unsigned, max_ampdu_len)
__field(u16, max_ampdu_frames)
__field(u16, ampdu_len)
__field(u16, ampdu_frames)
__field(u16, dma_len)
),
TP_fast_assign(
__assign_str(dev, dev_name(dev));
__entry->max_ampdu_len = max_ampdu_len;
__entry->max_ampdu_frames = max_ampdu_frames;
__entry->ampdu_len = ampdu_len;
__entry->ampdu_frames = ampdu_frames;
__entry->dma_len = dma_len;
),
TP_printk("[%s] ampdu session max_len=%u max_frames=%u len=%u frames=%u dma_len=%u",
__get_str(dev), __entry->max_ampdu_len,
__entry->max_ampdu_frames, __entry->ampdu_len,
__entry->ampdu_frames, __entry->dma_len)
);
#undef TRACE_SYSTEM
#define TRACE_SYSTEM brcmsmac_msg
#define MAX_MSG_LEN 100
DECLARE_EVENT_CLASS(brcms_msg_event,
TP_PROTO(struct va_format *vaf),
TP_ARGS(vaf),
TP_STRUCT__entry(
__dynamic_array(char, msg, MAX_MSG_LEN)
),
TP_fast_assign(
WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg),
MAX_MSG_LEN, vaf->fmt,
*vaf->va) >= MAX_MSG_LEN);
),
TP_printk("%s", __get_str(msg))
);
DEFINE_EVENT(brcms_msg_event, brcms_info,
TP_PROTO(struct va_format *vaf),
TP_ARGS(vaf)
);
DEFINE_EVENT(brcms_msg_event, brcms_warn,
TP_PROTO(struct va_format *vaf),
TP_ARGS(vaf)
);
DEFINE_EVENT(brcms_msg_event, brcms_err,
TP_PROTO(struct va_format *vaf),
TP_ARGS(vaf)
);
DEFINE_EVENT(brcms_msg_event, brcms_crit,
TP_PROTO(struct va_format *vaf),
TP_ARGS(vaf)
);
TRACE_EVENT(brcms_dbg,
TP_PROTO(u32 level, const char *func, struct va_format *vaf),
TP_ARGS(level, func, vaf),
TP_STRUCT__entry(
__field(u32, level)
__string(func, func)
__dynamic_array(char, msg, MAX_MSG_LEN)
),
TP_fast_assign(
__entry->level = level;
__assign_str(func, func);
WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg),
MAX_MSG_LEN, vaf->fmt,
*vaf->va) >= MAX_MSG_LEN);
),
TP_printk("%s: %s", __get_str(func), __get_str(msg))
);
#endif /* __TRACE_BRCMSMAC_H */
#ifdef CONFIG_BRCMDBG
#ifdef CONFIG_BRCM_TRACING
#undef TRACE_INCLUDE_PATH
#define TRACE_INCLUDE_PATH .
@ -89,4 +252,4 @@ TRACE_EVENT(brcms_dpc,
#include <trace/define_trace.h>
#endif /* CONFIG_BRCMDBG */
#endif /* CONFIG_BRCM_TRACING */

View File

@ -26,6 +26,7 @@
#include "stf.h"
#include "channel.h"
#include "mac80211_if.h"
#include "debug.h"
/* QDB() macro takes a dB value and converts to a quarter dB value */
#define QDB(n) ((n) * BRCMS_TXPWR_DB_FACTOR)
@ -336,8 +337,6 @@ struct brcms_cm_info *brcms_c_channel_mgr_attach(struct brcms_c_info *wlc)
const char *ccode = sprom->alpha2;
int ccode_len = sizeof(sprom->alpha2);
BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
wlc_cm = kzalloc(sizeof(struct brcms_cm_info), GFP_ATOMIC);
if (wlc_cm == NULL)
return NULL;
@ -615,8 +614,8 @@ brcms_c_valid_chanspec_ext(struct brcms_cm_info *wlc_cm, u16 chspec)
/* check the chanspec */
if (brcms_c_chspec_malformed(chspec)) {
wiphy_err(wlc->wiphy, "wl%d: malformed chanspec 0x%x\n",
wlc->pub->unit, chspec);
brcms_err(wlc->hw->d11core, "wl%d: malformed chanspec 0x%x\n",
wlc->pub->unit, chspec);
return false;
}
@ -738,7 +737,8 @@ static int brcms_reg_notifier(struct wiphy *wiphy,
mboolclr(wlc->pub->radio_disabled, WL_RADIO_COUNTRY_DISABLE);
} else {
mboolset(wlc->pub->radio_disabled, WL_RADIO_COUNTRY_DISABLE);
wiphy_err(wlc->wiphy, "wl%d: %s: no valid channel for \"%s\"\n",
brcms_err(wlc->hw->d11core,
"wl%d: %s: no valid channel for \"%s\"\n",
wlc->pub->unit, __func__, request->alpha2);
}

View File

@ -0,0 +1,44 @@
#include <linux/net.h>
#include "types.h"
#include "debug.h"
#include "brcms_trace_events.h"
#define __brcms_fn(fn) \
void __brcms_ ##fn(struct device *dev, const char *fmt, ...) \
{ \
struct va_format vaf = { \
.fmt = fmt, \
}; \
va_list args; \
\
va_start(args, fmt); \
vaf.va = &args; \
dev_ ##fn(dev, "%pV", &vaf); \
trace_brcms_ ##fn(&vaf); \
va_end(args); \
}
__brcms_fn(info)
__brcms_fn(warn)
__brcms_fn(err)
__brcms_fn(crit)
#if defined(CONFIG_BRCMDBG) || defined(CONFIG_BRCM_TRACING)
void __brcms_dbg(struct device *dev, u32 level, const char *func,
const char *fmt, ...)
{
struct va_format vaf = {
.fmt = fmt,
};
va_list args;
va_start(args, fmt);
vaf.va = &args;
#ifdef CONFIG_BRCMDBG
if ((brcm_msg_level & level) && net_ratelimit())
dev_err(dev, "%s %pV", func, &vaf);
#endif
trace_brcms_dbg(level, func, &vaf);
va_end(args);
}
#endif

View File

@ -0,0 +1,52 @@
#ifndef _BRCMS_DEBUG_H_
#define _BRCMS_DEBUG_H_
#include <linux/device.h>
#include <linux/bcma/bcma.h>
#include <net/cfg80211.h>
#include <net/mac80211.h>
#include "main.h"
#include "mac80211_if.h"
__printf(2, 3)
void __brcms_info(struct device *dev, const char *fmt, ...);
__printf(2, 3)
void __brcms_warn(struct device *dev, const char *fmt, ...);
__printf(2, 3)
void __brcms_err(struct device *dev, const char *fmt, ...);
__printf(2, 3)
void __brcms_crit(struct device *dev, const char *fmt, ...);
#if defined(CONFIG_BRCMDBG) || defined(CONFIG_BRCM_TRACING)
__printf(4, 5)
void __brcms_dbg(struct device *dev, u32 level, const char *func,
const char *fmt, ...);
#else
static inline __printf(4, 5)
void __brcms_dbg(struct device *dev, u32 level, const char *func,
const char *fmt, ...)
{
}
#endif
/*
* Debug macros cannot be used when wlc is uninitialized. Generally
* this means any code that could run before brcms_c_attach() has
* returned successfully probably shouldn't use the following macros.
*/
#define brcms_dbg(core, l, f, a...) __brcms_dbg(&(core)->dev, l, __func__, f, ##a)
#define brcms_info(core, f, a...) __brcms_info(&(core)->dev, f, ##a)
#define brcms_warn(core, f, a...) __brcms_warn(&(core)->dev, f, ##a)
#define brcms_err(core, f, a...) __brcms_err(&(core)->dev, f, ##a)
#define brcms_crit(core, f, a...) __brcms_crit(&(core)->dev, f, ##a)
#define brcms_dbg_info(core, f, a...) brcms_dbg(core, BRCM_DL_INFO, f, ##a)
#define brcms_dbg_mac80211(core, f, a...) brcms_dbg(core, BRCM_DL_MAC80211, f, ##a)
#define brcms_dbg_rx(core, f, a...) brcms_dbg(core, BRCM_DL_RX, f, ##a)
#define brcms_dbg_tx(core, f, a...) brcms_dbg(core, BRCM_DL_TX, f, ##a)
#define brcms_dbg_int(core, f, a...) brcms_dbg(core, BRCM_DL_INT, f, ##a)
#define brcms_dbg_dma(core, f, a...) brcms_dbg(core, BRCM_DL_DMA, f, ##a)
#define brcms_dbg_ht(core, f, a...) brcms_dbg(core, BRCM_DL_HT, f, ##a)
#endif /* _BRCMS_DEBUG_H_ */

View File

@ -14,17 +14,22 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/pci.h>
#include <net/cfg80211.h>
#include <net/mac80211.h>
#include <brcmu_utils.h>
#include <aiutils.h>
#include "types.h"
#include "main.h"
#include "dma.h"
#include "soc.h"
#include "scb.h"
#include "ampdu.h"
#include "debug.h"
#include "brcms_trace_events.h"
/*
* dma register field offset calculation
@ -176,28 +181,6 @@
#define BCMEXTRAHDROOM 172
/* debug/trace */
#ifdef DEBUG
#define DMA_ERROR(fmt, ...) \
do { \
if (*di->msg_level & 1) \
pr_debug("%s: " fmt, __func__, ##__VA_ARGS__); \
} while (0)
#define DMA_TRACE(fmt, ...) \
do { \
if (*di->msg_level & 2) \
pr_debug("%s: " fmt, __func__, ##__VA_ARGS__); \
} while (0)
#else
#define DMA_ERROR(fmt, ...) \
no_printk(fmt, ##__VA_ARGS__)
#define DMA_TRACE(fmt, ...) \
no_printk(fmt, ##__VA_ARGS__)
#endif /* DEBUG */
#define DMA_NONE(fmt, ...) \
no_printk(fmt, ##__VA_ARGS__)
#define MAXNAMEL 8 /* 8 char names */
/* macros to convert between byte offsets and indexes */
@ -224,12 +207,14 @@ struct dma64desc {
/* dma engine software state */
struct dma_info {
struct dma_pub dma; /* exported structure */
uint *msg_level; /* message level pointer */
char name[MAXNAMEL]; /* callers name for diag msgs */
struct bcma_device *core;
struct device *dmadev;
/* session information for AMPDU */
struct brcms_ampdu_session ampdu_session;
bool dma64; /* this dma engine is operating in 64-bit mode */
bool addrext; /* this dma engine supports DmaExtendedAddrChanges */
@ -298,12 +283,6 @@ struct dma_info {
bool aligndesc_4k;
};
/*
* default dma message level (if input msg_level
* pointer is null in dma_attach())
*/
static uint dma_msg_level;
/* Check for odd number of 1's */
static u32 parity32(__le32 data)
{
@ -353,7 +332,7 @@ static uint prevtxd(struct dma_info *di, uint i)
static uint nextrxd(struct dma_info *di, uint i)
{
return txd(di, i + 1);
return rxd(di, i + 1);
}
static uint ntxdactive(struct dma_info *di, uint h, uint t)
@ -371,7 +350,7 @@ static uint _dma_ctrlflags(struct dma_info *di, uint mask, uint flags)
uint dmactrlflags;
if (di == NULL) {
DMA_ERROR("NULL dma handle\n");
brcms_dbg_dma(di->core, "NULL dma handle\n");
return 0;
}
@ -423,13 +402,15 @@ static bool _dma_isaddrext(struct dma_info *di)
/* not all tx or rx channel are available */
if (di->d64txregbase != 0) {
if (!_dma64_addrext(di, DMA64TXREGOFFS(di, control)))
DMA_ERROR("%s: DMA64 tx doesn't have AE set\n",
di->name);
brcms_dbg_dma(di->core,
"%s: DMA64 tx doesn't have AE set\n",
di->name);
return true;
} else if (di->d64rxregbase != 0) {
if (!_dma64_addrext(di, DMA64RXREGOFFS(di, control)))
DMA_ERROR("%s: DMA64 rx doesn't have AE set\n",
di->name);
brcms_dbg_dma(di->core,
"%s: DMA64 rx doesn't have AE set\n",
di->name);
return true;
}
@ -530,8 +511,9 @@ static bool dma64_alloc(struct dma_info *di, uint direction)
va = dma_ringalloc(di, D64RINGALIGN, size, &align_bits,
&alloced, &di->txdpaorig);
if (va == NULL) {
DMA_ERROR("%s: DMA_ALLOC_CONSISTENT(ntxd) failed\n",
di->name);
brcms_dbg_dma(di->core,
"%s: DMA_ALLOC_CONSISTENT(ntxd) failed\n",
di->name);
return false;
}
align = (1 << align_bits);
@ -544,8 +526,9 @@ static bool dma64_alloc(struct dma_info *di, uint direction)
va = dma_ringalloc(di, D64RINGALIGN, size, &align_bits,
&alloced, &di->rxdpaorig);
if (va == NULL) {
DMA_ERROR("%s: DMA_ALLOC_CONSISTENT(nrxd) failed\n",
di->name);
brcms_dbg_dma(di->core,
"%s: DMA_ALLOC_CONSISTENT(nrxd) failed\n",
di->name);
return false;
}
align = (1 << align_bits);
@ -564,12 +547,13 @@ static bool _dma_alloc(struct dma_info *di, uint direction)
return dma64_alloc(di, direction);
}
struct dma_pub *dma_attach(char *name, struct si_pub *sih,
struct bcma_device *core,
struct dma_pub *dma_attach(char *name, struct brcms_c_info *wlc,
uint txregbase, uint rxregbase, uint ntxd, uint nrxd,
uint rxbufsize, int rxextheadroom,
uint nrxpost, uint rxoffset, uint *msg_level)
uint nrxpost, uint rxoffset)
{
struct si_pub *sih = wlc->hw->sih;
struct bcma_device *core = wlc->hw->d11core;
struct dma_info *di;
u8 rev = core->id.rev;
uint size;
@ -580,9 +564,6 @@ struct dma_pub *dma_attach(char *name, struct si_pub *sih,
if (di == NULL)
return NULL;
di->msg_level = msg_level ? msg_level : &dma_msg_level;
di->dma64 =
((bcma_aread32(core, BCMA_IOST) & SISF_DMA64) == SISF_DMA64);
@ -598,11 +579,11 @@ struct dma_pub *dma_attach(char *name, struct si_pub *sih,
*/
_dma_ctrlflags(di, DMA_CTRL_ROC | DMA_CTRL_PEN, 0);
DMA_TRACE("%s: %s flags 0x%x ntxd %d nrxd %d "
"rxbufsize %d rxextheadroom %d nrxpost %d rxoffset %d "
"txregbase %u rxregbase %u\n", name, "DMA64",
di->dma.dmactrlflags, ntxd, nrxd, rxbufsize,
rxextheadroom, nrxpost, rxoffset, txregbase, rxregbase);
brcms_dbg_dma(di->core, "%s: %s flags 0x%x ntxd %d nrxd %d "
"rxbufsize %d rxextheadroom %d nrxpost %d rxoffset %d "
"txregbase %u rxregbase %u\n", name, "DMA64",
di->dma.dmactrlflags, ntxd, nrxd, rxbufsize,
rxextheadroom, nrxpost, rxoffset, txregbase, rxregbase);
/* make a private copy of our callers name */
strncpy(di->name, name, MAXNAMEL);
@ -664,8 +645,8 @@ struct dma_pub *dma_attach(char *name, struct si_pub *sih,
di->dmadesc_align = 4; /* 16 byte alignment */
}
DMA_NONE("DMA descriptor align_needed %d, align %d\n",
di->aligndesc_4k, di->dmadesc_align);
brcms_dbg_dma(di->core, "DMA descriptor align_needed %d, align %d\n",
di->aligndesc_4k, di->dmadesc_align);
/* allocate tx packet pointer vector */
if (ntxd) {
@ -703,21 +684,27 @@ struct dma_pub *dma_attach(char *name, struct si_pub *sih,
if ((di->ddoffsetlow != 0) && !di->addrext) {
if (di->txdpa > SI_PCI_DMA_SZ) {
DMA_ERROR("%s: txdpa 0x%x: addrext not supported\n",
di->name, (u32)di->txdpa);
brcms_dbg_dma(di->core,
"%s: txdpa 0x%x: addrext not supported\n",
di->name, (u32)di->txdpa);
goto fail;
}
if (di->rxdpa > SI_PCI_DMA_SZ) {
DMA_ERROR("%s: rxdpa 0x%x: addrext not supported\n",
di->name, (u32)di->rxdpa);
brcms_dbg_dma(di->core,
"%s: rxdpa 0x%x: addrext not supported\n",
di->name, (u32)di->rxdpa);
goto fail;
}
}
DMA_TRACE("ddoffsetlow 0x%x ddoffsethigh 0x%x dataoffsetlow 0x%x dataoffsethigh 0x%x addrext %d\n",
di->ddoffsetlow, di->ddoffsethigh,
di->dataoffsetlow, di->dataoffsethigh,
di->addrext);
/* Initialize AMPDU session */
brcms_c_ampdu_reset_session(&di->ampdu_session, wlc);
brcms_dbg_dma(di->core,
"ddoffsetlow 0x%x ddoffsethigh 0x%x dataoffsetlow 0x%x dataoffsethigh 0x%x addrext %d\n",
di->ddoffsetlow, di->ddoffsethigh,
di->dataoffsetlow, di->dataoffsethigh,
di->addrext);
return (struct dma_pub *) di;
@ -763,7 +750,7 @@ void dma_detach(struct dma_pub *pub)
{
struct dma_info *di = (struct dma_info *)pub;
DMA_TRACE("%s:\n", di->name);
brcms_dbg_dma(di->core, "%s:\n", di->name);
/* free dma descriptor rings */
if (di->txd64)
@ -839,7 +826,7 @@ static void _dma_rxenable(struct dma_info *di)
uint dmactrlflags = di->dma.dmactrlflags;
u32 control;
DMA_TRACE("%s:\n", di->name);
brcms_dbg_dma(di->core, "%s:\n", di->name);
control = D64_RC_RE | (bcma_read32(di->core,
DMA64RXREGOFFS(di, control)) &
@ -859,7 +846,7 @@ void dma_rxinit(struct dma_pub *pub)
{
struct dma_info *di = (struct dma_info *)pub;
DMA_TRACE("%s:\n", di->name);
brcms_dbg_dma(di->core, "%s:\n", di->name);
if (di->nrxd == 0)
return;
@ -954,7 +941,7 @@ int dma_rx(struct dma_pub *pub, struct sk_buff_head *skb_list)
return 0;
len = le16_to_cpu(*(__le16 *) (p->data));
DMA_TRACE("%s: dma_rx len %d\n", di->name, len);
brcms_dbg_dma(di->core, "%s: dma_rx len %d\n", di->name, len);
dma_spin_for_len(len, p);
/* set actual length */
@ -981,14 +968,15 @@ int dma_rx(struct dma_pub *pub, struct sk_buff_head *skb_list)
DMA64RXREGOFFS(di, status0)) &
D64_RS0_CD_MASK) - di->rcvptrbase) &
D64_RS0_CD_MASK, struct dma64desc);
DMA_ERROR("rxin %d rxout %d, hw_curr %d\n",
di->rxin, di->rxout, cur);
brcms_dbg_dma(di->core,
"rxin %d rxout %d, hw_curr %d\n",
di->rxin, di->rxout, cur);
}
#endif /* DEBUG */
if ((di->dma.dmactrlflags & DMA_CTRL_RXMULTI) == 0) {
DMA_ERROR("%s: bad frame length (%d)\n",
di->name, len);
brcms_dbg_dma(di->core, "%s: bad frame length (%d)\n",
di->name, len);
skb_queue_walk_safe(&dma_frames, p, next) {
skb_unlink(p, &dma_frames);
brcmu_pkt_buf_free_skb(p);
@ -1005,7 +993,7 @@ int dma_rx(struct dma_pub *pub, struct sk_buff_head *skb_list)
static bool dma64_rxidle(struct dma_info *di)
{
DMA_TRACE("%s:\n", di->name);
brcms_dbg_dma(di->core, "%s:\n", di->name);
if (di->nrxd == 0)
return true;
@ -1016,6 +1004,17 @@ static bool dma64_rxidle(struct dma_info *di)
D64_RS0_CD_MASK));
}
static bool dma64_txidle(struct dma_info *di)
{
if (di->ntxd == 0)
return true;
return ((bcma_read32(di->core,
DMA64TXREGOFFS(di, status0)) & D64_XS0_CD_MASK) ==
(bcma_read32(di->core, DMA64TXREGOFFS(di, ptr)) &
D64_XS0_CD_MASK));
}
/*
* post receive buffers
* return false is refill failed completely and ring is empty this will stall
@ -1047,7 +1046,7 @@ bool dma_rxfill(struct dma_pub *pub)
n = di->nrxpost - nrxdactive(di, rxin, rxout);
DMA_TRACE("%s: post %d\n", di->name, n);
brcms_dbg_dma(di->core, "%s: post %d\n", di->name, n);
if (di->rxbufsize > BCMEXTRAHDROOM)
extra_offset = di->rxextrahdrroom;
@ -1060,9 +1059,11 @@ bool dma_rxfill(struct dma_pub *pub)
p = brcmu_pkt_buf_get_skb(di->rxbufsize + extra_offset);
if (p == NULL) {
DMA_ERROR("%s: out of rxbufs\n", di->name);
brcms_dbg_dma(di->core, "%s: out of rxbufs\n",
di->name);
if (i == 0 && dma64_rxidle(di)) {
DMA_ERROR("%s: ring is empty !\n", di->name);
brcms_dbg_dma(di->core, "%s: ring is empty !\n",
di->name);
ring_empty = true;
}
di->dma.rxnobuf++;
@ -1107,7 +1108,7 @@ void dma_rxreclaim(struct dma_pub *pub)
struct dma_info *di = (struct dma_info *)pub;
struct sk_buff *p;
DMA_TRACE("%s:\n", di->name);
brcms_dbg_dma(di->core, "%s:\n", di->name);
while ((p = _dma_getnextrxp(di, true)))
brcmu_pkt_buf_free_skb(p);
@ -1138,7 +1139,7 @@ void dma_txinit(struct dma_pub *pub)
struct dma_info *di = (struct dma_info *)pub;
u32 control = D64_XC_XE;
DMA_TRACE("%s:\n", di->name);
brcms_dbg_dma(di->core, "%s:\n", di->name);
if (di->ntxd == 0)
return;
@ -1170,7 +1171,7 @@ void dma_txsuspend(struct dma_pub *pub)
{
struct dma_info *di = (struct dma_info *)pub;
DMA_TRACE("%s:\n", di->name);
brcms_dbg_dma(di->core, "%s:\n", di->name);
if (di->ntxd == 0)
return;
@ -1182,7 +1183,7 @@ void dma_txresume(struct dma_pub *pub)
{
struct dma_info *di = (struct dma_info *)pub;
DMA_TRACE("%s:\n", di->name);
brcms_dbg_dma(di->core, "%s:\n", di->name);
if (di->ntxd == 0)
return;
@ -1205,11 +1206,11 @@ void dma_txreclaim(struct dma_pub *pub, enum txd_range range)
struct dma_info *di = (struct dma_info *)pub;
struct sk_buff *p;
DMA_TRACE("%s: %s\n",
di->name,
range == DMA_RANGE_ALL ? "all" :
range == DMA_RANGE_TRANSMITTED ? "transmitted" :
"transferred");
brcms_dbg_dma(di->core, "%s: %s\n",
di->name,
range == DMA_RANGE_ALL ? "all" :
range == DMA_RANGE_TRANSMITTED ? "transmitted" :
"transferred");
if (di->txin == di->txout)
return;
@ -1264,39 +1265,25 @@ bool dma_rxreset(struct dma_pub *pub)
return status == D64_RS0_RS_DISABLED;
}
/*
* !! tx entry routine
* WARNING: call must check the return value for error.
* the error(toss frames) could be fatal and cause many subsequent hard
* to debug problems
*/
int dma_txfast(struct dma_pub *pub, struct sk_buff *p, bool commit)
static void dma_txenq(struct dma_info *di, struct sk_buff *p)
{
struct dma_info *di = (struct dma_info *)pub;
unsigned char *data;
uint len;
u16 txout;
u32 flags = 0;
dma_addr_t pa;
DMA_TRACE("%s:\n", di->name);
txout = di->txout;
if (WARN_ON(nexttxd(di, txout) == di->txin))
return;
/*
* obtain and initialize transmit descriptor entry.
*/
data = p->data;
len = p->len;
/* no use to transmit a zero length packet */
if (len == 0)
return 0;
/* return nonzero if out of tx descriptors */
if (nexttxd(di, txout) == di->txin)
goto outoftxd;
/* get physical address of buffer start */
pa = dma_map_single(di->dmadev, data, len, DMA_TO_DEVICE);
@ -1318,23 +1305,147 @@ int dma_txfast(struct dma_pub *pub, struct sk_buff *p, bool commit)
/* bump the tx descriptor index */
di->txout = txout;
}
/* kick the chip */
if (commit)
bcma_write32(di->core, DMA64TXREGOFFS(di, ptr),
di->xmtptrbase + I2B(txout, struct dma64desc));
static void ampdu_finalize(struct dma_info *di)
{
struct brcms_ampdu_session *session = &di->ampdu_session;
struct sk_buff *p;
trace_brcms_ampdu_session(&session->wlc->hw->d11core->dev,
session->max_ampdu_len,
session->max_ampdu_frames,
session->ampdu_len,
skb_queue_len(&session->skb_list),
session->dma_len);
if (WARN_ON(skb_queue_empty(&session->skb_list)))
return;
brcms_c_ampdu_finalize(session);
while (!skb_queue_empty(&session->skb_list)) {
p = skb_dequeue(&session->skb_list);
dma_txenq(di, p);
}
bcma_write32(di->core, DMA64TXREGOFFS(di, ptr),
di->xmtptrbase + I2B(di->txout, struct dma64desc));
brcms_c_ampdu_reset_session(session, session->wlc);
}
static void prep_ampdu_frame(struct dma_info *di, struct sk_buff *p)
{
struct brcms_ampdu_session *session = &di->ampdu_session;
int ret;
ret = brcms_c_ampdu_add_frame(session, p);
if (ret == -ENOSPC) {
/*
* AMPDU cannot accomodate this frame. Close out the in-
* progress AMPDU session and start a new one.
*/
ampdu_finalize(di);
ret = brcms_c_ampdu_add_frame(session, p);
}
WARN_ON(ret);
}
/* Update count of available tx descriptors based on current DMA state */
static void dma_update_txavail(struct dma_info *di)
{
/*
* Available space is number of descriptors less the number of
* active descriptors and the number of queued AMPDU frames.
*/
di->dma.txavail = di->ntxd - ntxdactive(di, di->txin, di->txout) -
skb_queue_len(&di->ampdu_session.skb_list) - 1;
}
/*
* !! tx entry routine
* WARNING: call must check the return value for error.
* the error(toss frames) could be fatal and cause many subsequent hard
* to debug problems
*/
int dma_txfast(struct brcms_c_info *wlc, struct dma_pub *pub,
struct sk_buff *p)
{
struct dma_info *di = (struct dma_info *)pub;
struct brcms_ampdu_session *session = &di->ampdu_session;
struct ieee80211_tx_info *tx_info;
bool is_ampdu;
/* no use to transmit a zero length packet */
if (p->len == 0)
return 0;
/* return nonzero if out of tx descriptors */
if (di->dma.txavail == 0 || nexttxd(di, di->txout) == di->txin)
goto outoftxd;
tx_info = IEEE80211_SKB_CB(p);
is_ampdu = tx_info->flags & IEEE80211_TX_CTL_AMPDU;
if (is_ampdu)
prep_ampdu_frame(di, p);
else
dma_txenq(di, p);
/* tx flow control */
di->dma.txavail = di->ntxd - ntxdactive(di, di->txin, di->txout) - 1;
dma_update_txavail(di);
/* kick the chip */
if (is_ampdu) {
/*
* Start sending data if we've got a full AMPDU, there's
* no more space in the DMA ring, or the ring isn't
* currently transmitting.
*/
if (skb_queue_len(&session->skb_list) == session->max_ampdu_frames ||
di->dma.txavail == 0 || dma64_txidle(di))
ampdu_finalize(di);
} else {
bcma_write32(di->core, DMA64TXREGOFFS(di, ptr),
di->xmtptrbase + I2B(di->txout, struct dma64desc));
}
return 0;
outoftxd:
DMA_ERROR("%s: out of txds !!!\n", di->name);
brcms_dbg_dma(di->core, "%s: out of txds !!!\n", di->name);
brcmu_pkt_buf_free_skb(p);
di->dma.txavail = 0;
di->dma.txnobuf++;
return -1;
return -ENOSPC;
}
void dma_txflush(struct dma_pub *pub)
{
struct dma_info *di = (struct dma_info *)pub;
struct brcms_ampdu_session *session = &di->ampdu_session;
if (!skb_queue_empty(&session->skb_list))
ampdu_finalize(di);
}
int dma_txpending(struct dma_pub *pub)
{
struct dma_info *di = (struct dma_info *)pub;
return ntxdactive(di, di->txin, di->txout);
}
/*
* If we have an active AMPDU session and are not transmitting,
* this function will force tx to start.
*/
void dma_kick_tx(struct dma_pub *pub)
{
struct dma_info *di = (struct dma_info *)pub;
struct brcms_ampdu_session *session = &di->ampdu_session;
if (!skb_queue_empty(&session->skb_list) && dma64_txidle(di))
ampdu_finalize(di);
}
/*
@ -1354,11 +1465,11 @@ struct sk_buff *dma_getnexttxp(struct dma_pub *pub, enum txd_range range)
u16 active_desc;
struct sk_buff *txp;
DMA_TRACE("%s: %s\n",
di->name,
range == DMA_RANGE_ALL ? "all" :
range == DMA_RANGE_TRANSMITTED ? "transmitted" :
"transferred");
brcms_dbg_dma(di->core, "%s: %s\n",
di->name,
range == DMA_RANGE_ALL ? "all" :
range == DMA_RANGE_TRANSMITTED ? "transmitted" :
"transferred");
if (di->ntxd == 0)
return NULL;
@ -1412,13 +1523,13 @@ struct sk_buff *dma_getnexttxp(struct dma_pub *pub, enum txd_range range)
di->txin = i;
/* tx flow control */
di->dma.txavail = di->ntxd - ntxdactive(di, di->txin, di->txout) - 1;
dma_update_txavail(di);
return txp;
bogus:
DMA_NONE("bogus curr: start %d end %d txout %d\n",
start, end, di->txout);
brcms_dbg_dma(di->core, "bogus curr: start %d end %d txout %d\n",
start, end, di->txout);
return NULL;
}

View File

@ -74,12 +74,11 @@ struct dma_pub {
uint txnobuf; /* tx out of dma descriptors */
};
extern struct dma_pub *dma_attach(char *name, struct si_pub *sih,
struct bcma_device *d11core,
extern struct dma_pub *dma_attach(char *name, struct brcms_c_info *wlc,
uint txregbase, uint rxregbase,
uint ntxd, uint nrxd,
uint rxbufsize, int rxextheadroom,
uint nrxpost, uint rxoffset, uint *msg_level);
uint nrxpost, uint rxoffset);
void dma_rxinit(struct dma_pub *pub);
int dma_rx(struct dma_pub *pub, struct sk_buff_head *skb_list);
@ -87,7 +86,11 @@ bool dma_rxfill(struct dma_pub *pub);
bool dma_rxreset(struct dma_pub *pub);
bool dma_txreset(struct dma_pub *pub);
void dma_txinit(struct dma_pub *pub);
int dma_txfast(struct dma_pub *pub, struct sk_buff *p0, bool commit);
int dma_txfast(struct brcms_c_info *wlc, struct dma_pub *pub,
struct sk_buff *p0);
void dma_txflush(struct dma_pub *pub);
int dma_txpending(struct dma_pub *pub);
void dma_kick_tx(struct dma_pub *pub);
void dma_txsuspend(struct dma_pub *pub);
bool dma_txsuspended(struct dma_pub *pub);
void dma_txresume(struct dma_pub *pub);

View File

@ -33,6 +33,7 @@
#include "ucode_loader.h"
#include "mac80211_if.h"
#include "main.h"
#include "debug.h"
#define N_TX_QUEUES 4 /* #tx queues on mac80211<->driver interface */
@ -98,10 +99,14 @@ static struct bcma_device_id brcms_coreid_table[] = {
};
MODULE_DEVICE_TABLE(bcma, brcms_coreid_table);
#ifdef DEBUG
static int msglevel = 0xdeadbeef;
module_param(msglevel, int, 0);
#endif /* DEBUG */
#if defined(CONFIG_BRCMDBG)
/*
* Module parameter for setting the debug message level. Available
* flags are specified by the BRCM_DL_* macros in
* drivers/net/wireless/brcm80211/include/defs.h.
*/
module_param_named(debug, brcm_msg_level, uint, S_IRUGO | S_IWUSR);
#endif
static struct ieee80211_channel brcms_2ghz_chantable[] = {
CHAN2GHZ(1, 2412, IEEE80211_CHAN_NO_HT40MINUS),
@ -276,7 +281,7 @@ static void brcms_ops_tx(struct ieee80211_hw *hw,
spin_lock_bh(&wl->lock);
if (!wl->pub->up) {
wiphy_err(wl->wiphy, "ops->tx called while down\n");
brcms_err(wl->wlc->hw->d11core, "ops->tx called while down\n");
kfree_skb(skb);
goto done;
}
@ -313,8 +318,8 @@ static int brcms_ops_start(struct ieee80211_hw *hw)
spin_unlock_bh(&wl->lock);
if (err != 0)
wiphy_err(hw->wiphy, "%s: brcms_up() returned %d\n", __func__,
err);
brcms_err(wl->wlc->hw->d11core, "%s: brcms_up() returned %d\n",
__func__, err);
return err;
}
@ -332,7 +337,7 @@ static void brcms_ops_stop(struct ieee80211_hw *hw)
status = brcms_c_chipmatch(wl->wlc->hw->d11core);
spin_unlock_bh(&wl->lock);
if (!status) {
wiphy_err(wl->wiphy,
brcms_err(wl->wlc->hw->d11core,
"wl: brcms_ops_stop: chipmatch failed\n");
return;
}
@ -350,8 +355,9 @@ brcms_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
/* Just STA for now */
if (vif->type != NL80211_IFTYPE_STATION) {
wiphy_err(hw->wiphy, "%s: Attempt to add type %d, only"
" STA for now\n", __func__, vif->type);
brcms_err(wl->wlc->hw->d11core,
"%s: Attempt to add type %d, only STA for now\n",
__func__, vif->type);
return -EOPNOTSUPP;
}
@ -370,9 +376,9 @@ static int brcms_ops_config(struct ieee80211_hw *hw, u32 changed)
{
struct ieee80211_conf *conf = &hw->conf;
struct brcms_info *wl = hw->priv;
struct bcma_device *core = wl->wlc->hw->d11core;
int err = 0;
int new_int;
struct wiphy *wiphy = hw->wiphy;
spin_lock_bh(&wl->lock);
if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) {
@ -380,25 +386,26 @@ static int brcms_ops_config(struct ieee80211_hw *hw, u32 changed)
conf->listen_interval);
}
if (changed & IEEE80211_CONF_CHANGE_MONITOR)
wiphy_dbg(wiphy, "%s: change monitor mode: %s\n",
__func__, conf->flags & IEEE80211_CONF_MONITOR ?
"true" : "false");
brcms_dbg_info(core, "%s: change monitor mode: %s\n",
__func__, conf->flags & IEEE80211_CONF_MONITOR ?
"true" : "false");
if (changed & IEEE80211_CONF_CHANGE_PS)
wiphy_err(wiphy, "%s: change power-save mode: %s (implement)\n",
brcms_err(core, "%s: change power-save mode: %s (implement)\n",
__func__, conf->flags & IEEE80211_CONF_PS ?
"true" : "false");
if (changed & IEEE80211_CONF_CHANGE_POWER) {
err = brcms_c_set_tx_power(wl->wlc, conf->power_level);
if (err < 0) {
wiphy_err(wiphy, "%s: Error setting power_level\n",
brcms_err(core, "%s: Error setting power_level\n",
__func__);
goto config_out;
}
new_int = brcms_c_get_tx_power(wl->wlc);
if (new_int != conf->power_level)
wiphy_err(wiphy, "%s: Power level req != actual, %d %d"
"\n", __func__, conf->power_level,
brcms_err(core,
"%s: Power level req != actual, %d %d\n",
__func__, conf->power_level,
new_int);
}
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
@ -425,13 +432,13 @@ brcms_ops_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_bss_conf *info, u32 changed)
{
struct brcms_info *wl = hw->priv;
struct wiphy *wiphy = hw->wiphy;
struct bcma_device *core = wl->wlc->hw->d11core;
if (changed & BSS_CHANGED_ASSOC) {
/* association status changed (associated/disassociated)
* also implies a change in the AID.
*/
wiphy_err(wiphy, "%s: %s: %sassociated\n", KBUILD_MODNAME,
brcms_err(core, "%s: %s: %sassociated\n", KBUILD_MODNAME,
__func__, info->assoc ? "" : "dis");
spin_lock_bh(&wl->lock);
brcms_c_associate_upd(wl->wlc, info->assoc);
@ -491,7 +498,7 @@ brcms_ops_bss_info_changed(struct ieee80211_hw *hw,
error = brcms_c_set_rateset(wl->wlc, &rs);
spin_unlock_bh(&wl->lock);
if (error)
wiphy_err(wiphy, "changing basic rates failed: %d\n",
brcms_err(core, "changing basic rates failed: %d\n",
error);
}
if (changed & BSS_CHANGED_BEACON_INT) {
@ -508,30 +515,30 @@ brcms_ops_bss_info_changed(struct ieee80211_hw *hw,
}
if (changed & BSS_CHANGED_BEACON)
/* Beacon data changed, retrieve new beacon (beaconing modes) */
wiphy_err(wiphy, "%s: beacon changed\n", __func__);
brcms_err(core, "%s: beacon changed\n", __func__);
if (changed & BSS_CHANGED_BEACON_ENABLED) {
/* Beaconing should be enabled/disabled (beaconing modes) */
wiphy_err(wiphy, "%s: Beacon enabled: %s\n", __func__,
brcms_err(core, "%s: Beacon enabled: %s\n", __func__,
info->enable_beacon ? "true" : "false");
}
if (changed & BSS_CHANGED_CQM) {
/* Connection quality monitor config changed */
wiphy_err(wiphy, "%s: cqm change: threshold %d, hys %d "
brcms_err(core, "%s: cqm change: threshold %d, hys %d "
" (implement)\n", __func__, info->cqm_rssi_thold,
info->cqm_rssi_hyst);
}
if (changed & BSS_CHANGED_IBSS) {
/* IBSS join status changed */
wiphy_err(wiphy, "%s: IBSS joined: %s (implement)\n", __func__,
info->ibss_joined ? "true" : "false");
brcms_err(core, "%s: IBSS joined: %s (implement)\n",
__func__, info->ibss_joined ? "true" : "false");
}
if (changed & BSS_CHANGED_ARP_FILTER) {
/* Hardware ARP filter address list or state changed */
wiphy_err(wiphy, "%s: arp filtering: enabled %s, count %d"
brcms_err(core, "%s: arp filtering: enabled %s, count %d"
" (implement)\n", __func__, info->arp_filter_enabled ?
"true" : "false", info->arp_addr_cnt);
}
@ -541,8 +548,8 @@ brcms_ops_bss_info_changed(struct ieee80211_hw *hw,
* QoS for this association was enabled/disabled.
* Note that it is only ever disabled for station mode.
*/
wiphy_err(wiphy, "%s: qos enabled: %s (implement)\n", __func__,
info->qos ? "true" : "false");
brcms_err(core, "%s: qos enabled: %s (implement)\n",
__func__, info->qos ? "true" : "false");
}
return;
}
@ -553,25 +560,25 @@ brcms_ops_configure_filter(struct ieee80211_hw *hw,
unsigned int *total_flags, u64 multicast)
{
struct brcms_info *wl = hw->priv;
struct wiphy *wiphy = hw->wiphy;
struct bcma_device *core = wl->wlc->hw->d11core;
changed_flags &= MAC_FILTERS;
*total_flags &= MAC_FILTERS;
if (changed_flags & FIF_PROMISC_IN_BSS)
wiphy_dbg(wiphy, "FIF_PROMISC_IN_BSS\n");
brcms_dbg_info(core, "FIF_PROMISC_IN_BSS\n");
if (changed_flags & FIF_ALLMULTI)
wiphy_dbg(wiphy, "FIF_ALLMULTI\n");
brcms_dbg_info(core, "FIF_ALLMULTI\n");
if (changed_flags & FIF_FCSFAIL)
wiphy_dbg(wiphy, "FIF_FCSFAIL\n");
brcms_dbg_info(core, "FIF_FCSFAIL\n");
if (changed_flags & FIF_CONTROL)
wiphy_dbg(wiphy, "FIF_CONTROL\n");
brcms_dbg_info(core, "FIF_CONTROL\n");
if (changed_flags & FIF_OTHER_BSS)
wiphy_dbg(wiphy, "FIF_OTHER_BSS\n");
brcms_dbg_info(core, "FIF_OTHER_BSS\n");
if (changed_flags & FIF_PSPOLL)
wiphy_dbg(wiphy, "FIF_PSPOLL\n");
brcms_dbg_info(core, "FIF_PSPOLL\n");
if (changed_flags & FIF_BCN_PRBRESP_PROMISC)
wiphy_dbg(wiphy, "FIF_BCN_PRBRESP_PROMISC\n");
brcms_dbg_info(core, "FIF_BCN_PRBRESP_PROMISC\n");
spin_lock_bh(&wl->lock);
brcms_c_mac_promisc(wl->wlc, *total_flags);
@ -653,8 +660,8 @@ brcms_ops_ampdu_action(struct ieee80211_hw *hw,
status = brcms_c_aggregatable(wl->wlc, tid);
spin_unlock_bh(&wl->lock);
if (!status) {
wiphy_err(wl->wiphy, "START: tid %d is not agg\'able\n",
tid);
brcms_err(wl->wlc->hw->d11core,
"START: tid %d is not agg\'able\n", tid);
return -EINVAL;
}
ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
@ -681,8 +688,8 @@ brcms_ops_ampdu_action(struct ieee80211_hw *hw,
/* Power save wakeup */
break;
default:
wiphy_err(wl->wiphy, "%s: Invalid command, ignoring\n",
__func__);
brcms_err(wl->wlc->hw->d11core,
"%s: Invalid command, ignoring\n", __func__);
}
return 0;
@ -1144,14 +1151,13 @@ static int brcms_suspend(struct bcma_device *pdev)
wl->pub->hw_up = false;
spin_unlock_bh(&wl->lock);
pr_debug("brcms_suspend ok\n");
brcms_dbg_info(wl->wlc->hw->d11core, "brcms_suspend ok\n");
return 0;
}
static int brcms_resume(struct bcma_device *pdev)
{
pr_debug("brcms_resume ok\n");
return 0;
}
@ -1184,10 +1190,6 @@ static DECLARE_WORK(brcms_driver_work, brcms_driver_init);
static int __init brcms_module_init(void)
{
#ifdef DEBUG
if (msglevel != 0xdeadbeef)
brcm_msg_level = msglevel;
#endif
if (!schedule_work(&brcms_driver_work))
return -EBUSY;
@ -1216,7 +1218,7 @@ module_exit(brcms_module_exit);
void brcms_txflowcontrol(struct brcms_info *wl, struct brcms_if *wlif,
bool state, int prio)
{
wiphy_err(wl->wiphy, "Shouldn't be here %s\n", __func__);
brcms_err(wl->wlc->hw->d11core, "Shouldn't be here %s\n", __func__);
}
/*
@ -1224,7 +1226,8 @@ void brcms_txflowcontrol(struct brcms_info *wl, struct brcms_if *wlif,
*/
void brcms_init(struct brcms_info *wl)
{
BCMMSG(wl->pub->ieee_hw->wiphy, "wl%d\n", wl->pub->unit);
brcms_dbg_info(wl->wlc->hw->d11core, "Initializing wl%d\n",
wl->pub->unit);
brcms_reset(wl);
brcms_c_init(wl->wlc, wl->mute_tx);
}
@ -1234,7 +1237,7 @@ void brcms_init(struct brcms_info *wl)
*/
uint brcms_reset(struct brcms_info *wl)
{
BCMMSG(wl->pub->ieee_hw->wiphy, "wl%d\n", wl->pub->unit);
brcms_dbg_info(wl->wlc->hw->d11core, "Resetting wl%d\n", wl->pub->unit);
brcms_c_reset(wl->wlc);
/* dpc will not be rescheduled */
@ -1248,7 +1251,7 @@ uint brcms_reset(struct brcms_info *wl)
void brcms_fatal_error(struct brcms_info *wl)
{
wiphy_err(wl->wlc->wiphy, "wl%d: fatal error, reinitializing\n",
brcms_err(wl->wlc->hw->d11core, "wl%d: fatal error, reinitializing\n",
wl->wlc->pub->unit);
brcms_reset(wl);
ieee80211_restart_hw(wl->pub->ieee_hw);
@ -1396,8 +1399,9 @@ void brcms_add_timer(struct brcms_timer *t, uint ms, int periodic)
#ifdef DEBUG
if (t->set)
wiphy_err(hw->wiphy, "%s: Already set. Name: %s, per %d\n",
__func__, t->name, periodic);
brcms_dbg_info(t->wl->wlc->hw->d11core,
"%s: Already set. Name: %s, per %d\n",
__func__, t->name, periodic);
#endif
t->ms = ms;
t->periodic = (bool) periodic;
@ -1486,8 +1490,8 @@ int brcms_ucode_init_buf(struct brcms_info *wl, void **pbuf, u32 idx)
}
}
}
wiphy_err(wl->wiphy, "ERROR: ucode buf tag:%d can not be found!\n",
idx);
brcms_err(wl->wlc->hw->d11core,
"ERROR: ucode buf tag:%d can not be found!\n", idx);
*pbuf = NULL;
fail:
return -ENODATA;
@ -1510,7 +1514,7 @@ int brcms_ucode_init_uint(struct brcms_info *wl, size_t *n_bytes, u32 idx)
pdata = wl->fw.fw_bin[i]->data +
le32_to_cpu(hdr->offset);
if (le32_to_cpu(hdr->len) != 4) {
wiphy_err(wl->wiphy,
brcms_err(wl->wlc->hw->d11core,
"ERROR: fw hdr len\n");
return -ENOMSG;
}
@ -1519,7 +1523,8 @@ int brcms_ucode_init_uint(struct brcms_info *wl, size_t *n_bytes, u32 idx)
}
}
}
wiphy_err(wl->wiphy, "ERROR: ucode tag:%d can not be found!\n", idx);
brcms_err(wl->wlc->hw->d11core,
"ERROR: ucode tag:%d can not be found!\n", idx);
return -ENOMSG;
}
@ -1560,8 +1565,8 @@ int brcms_check_firmwares(struct brcms_info *wl)
sizeof(struct firmware_hdr));
rc = -EBADF;
} else if (fw->size < MIN_FW_SIZE || fw->size > MAX_FW_SIZE) {
wiphy_err(wl->wiphy, "%s: out of bounds fw file size "
"%zu\n", __func__, fw->size);
wiphy_err(wl->wiphy, "%s: out of bounds fw file size %zu\n",
__func__, fw->size);
rc = -EBADF;
} else {
/* check if ucode section overruns firmware image */

File diff suppressed because it is too large Load Diff

View File

@ -101,9 +101,6 @@
#define DATA_BLOCK_TX_SUPR (1 << 4)
/* 802.1D Priority to TX FIFO number for wme */
extern const u8 prio2fifo[];
/* Ucode MCTL_WAKE override bits */
#define BRCMS_WAKE_OVERRIDE_CLKCTL 0x01
#define BRCMS_WAKE_OVERRIDE_PHYREG 0x02
@ -242,7 +239,6 @@ struct brcms_core {
/* fifo */
uint *txavail[NFIFO]; /* # tx descriptors available */
s16 txpktpend[NFIFO]; /* tx admission control */
struct macstat *macstat_snapshot; /* mac hw prev read values */
};
@ -382,19 +378,6 @@ struct brcms_hardware {
*/
};
/* TX Queue information
*
* Each flow of traffic out of the device has a TX Queue with independent
* flow control. Several interfaces may be associated with a single TX Queue
* if they belong to the same flow of traffic from the device. For multi-channel
* operation there are independent TX Queues for each channel.
*/
struct brcms_txq_info {
struct brcms_txq_info *next;
struct pktq q;
uint stopped; /* tx flow control bits */
};
/*
* Principal common driver data structure.
*
@ -435,11 +418,8 @@ struct brcms_txq_info {
* WDlast: last time wlc_watchdog() was called.
* edcf_txop[IEEE80211_NUM_ACS]: current txop for each ac.
* wme_retries: per-AC retry limits.
* tx_prec_map: Precedence map based on HW FIFO space.
* fifo2prec_map[NFIFO]: pointer to fifo2_prec map based on WME.
* bsscfg: set of BSS configurations, idx 0 is default and always valid.
* cfg: the primary bsscfg (can be AP or STA).
* tx_queues: common TX Queue list.
* modulecb:
* mimoft: SIGN or 11N.
* cck_40txbw: 11N, cck tx b/w override when in 40MHZ mode.
@ -469,7 +449,6 @@ struct brcms_txq_info {
* tempsense_lasttime;
* tx_duty_cycle_ofdm: maximum allowed duty cycle for OFDM.
* tx_duty_cycle_cck: maximum allowed duty cycle for CCK.
* pkt_queue: txq for transmit packets.
* wiphy:
* pri_scb: primary Station Control Block
*/
@ -533,14 +512,9 @@ struct brcms_c_info {
u16 edcf_txop[IEEE80211_NUM_ACS];
u16 wme_retries[IEEE80211_NUM_ACS];
u16 tx_prec_map;
u16 fifo2prec_map[NFIFO];
struct brcms_bss_cfg *bsscfg;
/* tx queue */
struct brcms_txq_info *tx_queues;
struct modulecb *modulecb;
u8 mimoft;
@ -585,7 +559,6 @@ struct brcms_c_info {
u16 tx_duty_cycle_ofdm;
u16 tx_duty_cycle_cck;
struct brcms_txq_info *pkt_queue;
struct wiphy *wiphy;
struct scb pri_scb;
};
@ -637,30 +610,13 @@ struct brcms_bss_cfg {
struct brcms_bss_info *current_bss;
};
extern void brcms_c_txfifo(struct brcms_c_info *wlc, uint fifo,
struct sk_buff *p,
bool commit, s8 txpktpend);
extern void brcms_c_txfifo_complete(struct brcms_c_info *wlc, uint fifo,
s8 txpktpend);
extern void brcms_c_txq_enq(struct brcms_c_info *wlc, struct scb *scb,
struct sk_buff *sdu, uint prec);
extern void brcms_c_print_txstatus(struct tx_status *txs);
extern int brcms_c_txfifo(struct brcms_c_info *wlc, uint fifo,
struct sk_buff *p);
extern int brcms_b_xmtfifo_sz_get(struct brcms_hardware *wlc_hw, uint fifo,
uint *blocks);
#if defined(DEBUG)
extern void brcms_c_print_txdesc(struct d11txh *txh);
#else
static inline void brcms_c_print_txdesc(struct d11txh *txh)
{
}
#endif
extern int brcms_c_set_gmode(struct brcms_c_info *wlc, u8 gmode, bool config);
extern void brcms_c_mac_promisc(struct brcms_c_info *wlc, uint filter_flags);
extern void brcms_c_send_q(struct brcms_c_info *wlc);
extern int brcms_c_prep_pdu(struct brcms_c_info *wlc, struct sk_buff *pdu,
uint *fifo);
extern u16 brcms_c_calc_lsig_len(struct brcms_c_info *wlc, u32 ratespec,
uint mac_len);
extern u32 brcms_c_rspec_to_rts_rspec(struct brcms_c_info *wlc,

View File

@ -200,43 +200,6 @@ enum wlc_par_id {
/* WL11N Support */
#define AMPDU_AGG_HOST 1
/* pri is priority encoded in the packet. This maps the Packet priority to
* enqueue precedence as defined in wlc_prec_map
*/
extern const u8 wlc_prio2prec_map[];
#define BRCMS_PRIO_TO_PREC(pri) wlc_prio2prec_map[(pri) & 7]
#define BRCMS_PREC_COUNT 16 /* Max precedence level implemented */
/* Mask to describe all precedence levels */
#define BRCMS_PREC_BMP_ALL MAXBITVAL(BRCMS_PREC_COUNT)
/*
* This maps priority to one precedence higher - Used by PS-Poll response
* packets to simulate enqueue-at-head operation, but still maintain the
* order on the queue
*/
#define BRCMS_PRIO_TO_HI_PREC(pri) min(BRCMS_PRIO_TO_PREC(pri) + 1,\
BRCMS_PREC_COUNT - 1)
/* Define a bitmap of precedences comprised by each AC */
#define BRCMS_PREC_BMP_AC_BE (NBITVAL(BRCMS_PRIO_TO_PREC(PRIO_8021D_BE)) | \
NBITVAL(BRCMS_PRIO_TO_HI_PREC(PRIO_8021D_BE)) | \
NBITVAL(BRCMS_PRIO_TO_PREC(PRIO_8021D_EE)) | \
NBITVAL(BRCMS_PRIO_TO_HI_PREC(PRIO_8021D_EE)))
#define BRCMS_PREC_BMP_AC_BK (NBITVAL(BRCMS_PRIO_TO_PREC(PRIO_8021D_BK)) | \
NBITVAL(BRCMS_PRIO_TO_HI_PREC(PRIO_8021D_BK)) | \
NBITVAL(BRCMS_PRIO_TO_PREC(PRIO_8021D_NONE)) | \
NBITVAL(BRCMS_PRIO_TO_HI_PREC(PRIO_8021D_NONE)))
#define BRCMS_PREC_BMP_AC_VI (NBITVAL(BRCMS_PRIO_TO_PREC(PRIO_8021D_CL)) | \
NBITVAL(BRCMS_PRIO_TO_HI_PREC(PRIO_8021D_CL)) | \
NBITVAL(BRCMS_PRIO_TO_PREC(PRIO_8021D_VI)) | \
NBITVAL(BRCMS_PRIO_TO_HI_PREC(PRIO_8021D_VI)))
#define BRCMS_PREC_BMP_AC_VO (NBITVAL(BRCMS_PRIO_TO_PREC(PRIO_8021D_VO)) | \
NBITVAL(BRCMS_PRIO_TO_HI_PREC(PRIO_8021D_VO)) | \
NBITVAL(BRCMS_PRIO_TO_PREC(PRIO_8021D_NC)) | \
NBITVAL(BRCMS_PRIO_TO_HI_PREC(PRIO_8021D_NC)))
/* network protection config */
#define BRCMS_PROT_G_SPEC 1 /* SPEC g protection */
#define BRCMS_PROT_G_OVR 2 /* SPEC g prot override */

View File

@ -23,6 +23,7 @@
#include "channel.h"
#include "main.h"
#include "stf.h"
#include "debug.h"
#define MIN_SPATIAL_EXPANSION 0
#define MAX_SPATIAL_EXPANSION 1
@ -160,8 +161,8 @@ bool brcms_c_stf_stbc_rx_set(struct brcms_c_info *wlc, s32 int_val)
static int brcms_c_stf_txcore_set(struct brcms_c_info *wlc, u8 Nsts,
u8 core_mask)
{
BCMMSG(wlc->wiphy, "wl%d: Nsts %d core_mask %x\n",
wlc->pub->unit, Nsts, core_mask);
brcms_dbg_ht(wlc->hw->d11core, "wl%d: Nsts %d core_mask %x\n",
wlc->pub->unit, Nsts, core_mask);
if (hweight8(core_mask) > wlc->stf->txstreams)
core_mask = 0;
@ -194,7 +195,8 @@ static int brcms_c_stf_spatial_policy_set(struct brcms_c_info *wlc, int val)
int i;
u8 core_mask = 0;
BCMMSG(wlc->wiphy, "wl%d: val %x\n", wlc->pub->unit, val);
brcms_dbg_ht(wlc->hw->d11core, "wl%d: val %x\n", wlc->pub->unit,
val);
wlc->stf->spatial_policy = (s8) val;
for (i = 1; i <= MAX_STREAMS_SUPPORTED; i++) {

Some files were not shown because too many files have changed in this diff Show More