Skip to content
Navigation Menu
Toggle navigation
Sign in
In this repository
All GitHub Enterprise
↵
Jump to
↵
No suggested jump to results
In this repository
All GitHub Enterprise
↵
Jump to
↵
In this organization
All GitHub Enterprise
↵
Jump to
↵
In this repository
All GitHub Enterprise
↵
Jump to
↵
Sign in
Reseting focus
You signed in with another tab or window.
Reload
to refresh your session.
You signed out in another tab or window.
Reload
to refresh your session.
You switched accounts on another tab or window.
Reload
to refresh your session.
Dismiss alert
{{ message }}
mariux64
/
linux
Public
Notifications
You must be signed in to change notification settings
Fork
0
Star
0
Code
Issues
2
Pull requests
0
Actions
Projects
0
Wiki
Security
Insights
Additional navigation options
Code
Issues
Pull requests
Actions
Projects
Wiki
Security
Insights
Files
e5f0a27
Documentation
arch
block
crypto
drivers
accessibility
acpi
amba
ata
atm
auxdisplay
base
bcma
block
bluetooth
cdrom
char
clk
clocksource
connector
cpufreq
cpuidle
crypto
dca
devfreq
dio
dma
edac
eisa
firewire
firmware
gpio
gpu
hid
hv
hwmon
hwspinlock
i2c
ide
idle
ieee802154
infiniband
input
iommu
isdn
leds
lguest
macintosh
mca
md
media
memstick
message
mfd
misc
mmc
mtd
net
appletalk
arcnet
bonding
caif
can
cris
ethernet
fddi
hamradio
hippi
irda
phy
plip
ppp
slip
tokenring
usb
vmxnet3
wan
wimax
wireless
ath
ath5k
ath6kl
ath9k
Kconfig
Makefile
ahb.c
ani.c
ani.h
ar5008_initvals.h
ar5008_phy.c
ar9001_initvals.h
ar9002_calib.c
ar9002_hw.c
ar9002_initvals.h
ar9002_mac.c
ar9002_phy.c
ar9002_phy.h
ar9003_2p2_initvals.h
ar9003_calib.c
ar9003_eeprom.c
ar9003_eeprom.h
ar9003_hw.c
ar9003_mac.c
ar9003_mac.h
ar9003_mci.c
ar9003_mci.h
ar9003_paprd.c
ar9003_phy.c
ar9003_phy.h
ar9003_rtt.c
ar9003_rtt.h
ar9330_1p1_initvals.h
ar9330_1p2_initvals.h
ar9340_initvals.h
ar9462_1p0_initvals.h
ar9462_2p0_initvals.h
ar9485_initvals.h
ar9580_1p0_initvals.h
ath9k.h
beacon.c
btcoex.c
btcoex.h
calib.c
calib.h
common.c
common.h
debug.c
debug.h
eeprom.c
eeprom.h
eeprom_4k.c
eeprom_9287.c
eeprom_def.c
gpio.c
hif_usb.c
hif_usb.h
htc.h
htc_drv_beacon.c
htc_drv_debug.c
htc_drv_gpio.c
htc_drv_init.c
htc_drv_main.c
htc_drv_txrx.c
htc_hst.c
htc_hst.h
hw-ops.h
hw.c
hw.h
init.c
mac.c
mac.h
main.c
mci.c
mci.h
pci.c
phy.h
rc.c
rc.h
recv.c
reg.h
wmi.c
wmi.h
xmit.c
carl9170
Kconfig
Makefile
ath.h
debug.c
hw.c
key.c
main.c
reg.h
regd.c
regd.h
regd_common.h
b43
b43legacy
brcm80211
hostap
ipw2x00
iwlegacy
iwlwifi
iwmc3200wifi
libertas
libertas_tf
mwifiex
orinoco
p54
prism54
rt2x00
rtl818x
rtlwifi
wl1251
wl12xx
zd1211rw
Kconfig
Makefile
adm8211.c
adm8211.h
airo.c
airo.h
airo_cs.c
at76c50x-usb.c
at76c50x-usb.h
atmel.c
atmel.h
atmel_cs.c
atmel_pci.c
mac80211_hwsim.c
mac80211_hwsim.h
mwl8k.c
ray_cs.c
ray_cs.h
rayctl.h
rndis_wlan.c
wl3501.h
wl3501_cs.c
zd1201.c
zd1201.h
xen-netback
Kconfig
LICENSE.SRC
Makefile
Space.c
dummy.c
eql.c
ifb.c
loopback.c
macvlan.c
macvtap.c
mdio.c
mii.c
netconsole.c
rionet.c
sb1000.c
sungem_phy.c
tun.c
veth.c
virtio_net.c
xen-netfront.c
nfc
nubus
of
oprofile
parisc
parport
pci
pcmcia
pinctrl
platform
pnp
power
pps
ps3
ptp
rapidio
regulator
rtc
s390
sbus
scsi
sfi
sh
sn
spi
ssb
staging
target
tc
telephony
thermal
tty
uio
usb
uwb
vhost
video
virt
virtio
vlynq
w1
watchdog
xen
zorro
Kconfig
Makefile
firmware
fs
include
init
ipc
kernel
lib
mm
net
samples
scripts
security
sound
tools
usr
virt/kvm
.gitignore
.mailmap
COPYING
CREDITS
Kbuild
Kconfig
MAINTAINERS
Makefile
README
REPORTING-BUGS
Breadcrumbs
linux
/
drivers
/
net
/
wireless
/
ath
/
ath9k
/
mci.c
Copy path
Blame
Blame
Latest commit
History
History
673 lines (552 loc) · 18.1 KB
Breadcrumbs
linux
/
drivers
/
net
/
wireless
/
ath
/
ath9k
/
mci.c
Top
File metadata and controls
Code
Blame
673 lines (552 loc) · 18.1 KB
Raw
/* * Copyright (c) 2010-2011 Atheros Communications 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 <linux/dma-mapping.h> #include <linux/slab.h> #include "ath9k.h" #include "mci.h" u8 ath_mci_duty_cycle[] = { 0, 50, 60, 70, 80, 85, 90, 95, 98 }; static struct ath_mci_profile_info* ath_mci_find_profile(struct ath_mci_profile *mci, struct ath_mci_profile_info *info) { struct ath_mci_profile_info *entry; list_for_each_entry(entry, &mci->info, list) { if (entry->conn_handle == info->conn_handle) break; } return entry; } static bool ath_mci_add_profile(struct ath_common *common, struct ath_mci_profile *mci, struct ath_mci_profile_info *info) { struct ath_mci_profile_info *entry; if ((mci->num_sco == ATH_MCI_MAX_SCO_PROFILE) && (info->type == MCI_GPM_COEX_PROFILE_VOICE)) { ath_dbg(common, ATH_DBG_MCI, "Too many SCO profile, failed to add new profile\n"); return false; } if (((NUM_PROF(mci) - mci->num_sco) == ATH_MCI_MAX_ACL_PROFILE) && (info->type != MCI_GPM_COEX_PROFILE_VOICE)) { ath_dbg(common, ATH_DBG_MCI, "Too many ACL profile, failed to add new profile\n"); return false; } entry = ath_mci_find_profile(mci, info); if (entry) memcpy(entry, info, 10); else { entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (!entry) return false; memcpy(entry, info, 10); INC_PROF(mci, info); list_add_tail(&info->list, &mci->info); } return true; } static void ath_mci_del_profile(struct ath_common *common, struct ath_mci_profile *mci, struct ath_mci_profile_info *info) { struct ath_mci_profile_info *entry; entry = ath_mci_find_profile(mci, info); if (!entry) { ath_dbg(common, ATH_DBG_MCI, "Profile to be deleted not found\n"); return; } DEC_PROF(mci, entry); list_del(&entry->list); kfree(entry); } void ath_mci_flush_profile(struct ath_mci_profile *mci) { struct ath_mci_profile_info *info, *tinfo; list_for_each_entry_safe(info, tinfo, &mci->info, list) { list_del(&info->list); DEC_PROF(mci, info); kfree(info); } mci->aggr_limit = 0; } static void ath_mci_adjust_aggr_limit(struct ath_btcoex *btcoex) { struct ath_mci_profile *mci = &btcoex->mci; u32 wlan_airtime = btcoex->btcoex_period * (100 - btcoex->duty_cycle) / 100; /* * Scale: wlan_airtime is in ms, aggr_limit is in 0.25 ms. * When wlan_airtime is less than 4ms, aggregation limit has to be * adjusted half of wlan_airtime to ensure that the aggregation can fit * without collision with BT traffic. */ if ((wlan_airtime <= 4) && (!mci->aggr_limit || (mci->aggr_limit > (2 * wlan_airtime)))) mci->aggr_limit = 2 * wlan_airtime; } static void ath_mci_update_scheme(struct ath_softc *sc) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_btcoex *btcoex = &sc->btcoex; struct ath_mci_profile *mci = &btcoex->mci; struct ath_mci_profile_info *info; u32 num_profile = NUM_PROF(mci); if (num_profile == 1) { info = list_first_entry(&mci->info, struct ath_mci_profile_info, list); if (mci->num_sco && info->T == 12) { mci->aggr_limit = 8; ath_dbg(common, ATH_DBG_MCI, "Single SCO, aggregation limit 2 ms\n"); } else if ((info->type == MCI_GPM_COEX_PROFILE_BNEP) && !info->master) { btcoex->btcoex_period = 60; ath_dbg(common, ATH_DBG_MCI, "Single slave PAN/FTP, bt period 60 ms\n"); } else if ((info->type == MCI_GPM_COEX_PROFILE_HID) && (info->T > 0 && info->T < 50) && (info->A > 1 || info->W > 1)) { btcoex->duty_cycle = 30; mci->aggr_limit = 8; ath_dbg(common, ATH_DBG_MCI, "Multiple attempt/timeout single HID " "aggregation limit 2 ms dutycycle 30%%\n"); } } else if ((num_profile == 2) && (mci->num_hid == 2)) { btcoex->duty_cycle = 30; mci->aggr_limit = 8; ath_dbg(common, ATH_DBG_MCI, "Two HIDs aggregation limit 2 ms dutycycle 30%%\n"); } else if (num_profile > 3) { mci->aggr_limit = 6; ath_dbg(common, ATH_DBG_MCI, "Three or more profiles aggregation limit 1.5 ms\n"); } if (IS_CHAN_2GHZ(sc->sc_ah->curchan)) { if (IS_CHAN_HT(sc->sc_ah->curchan)) ath_mci_adjust_aggr_limit(btcoex); else btcoex->btcoex_period >>= 1; } ath9k_hw_btcoex_disable(sc->sc_ah); ath9k_btcoex_timer_pause(sc); if (IS_CHAN_5GHZ(sc->sc_ah->curchan)) return; btcoex->duty_cycle += (mci->num_bdr ? ATH_MCI_MAX_DUTY_CYCLE : 0); if (btcoex->duty_cycle > ATH_MCI_MAX_DUTY_CYCLE) btcoex->duty_cycle = ATH_MCI_MAX_DUTY_CYCLE; btcoex->btcoex_period *= 1000; btcoex->btcoex_no_stomp = btcoex->btcoex_period * (100 - btcoex->duty_cycle) / 100; ath9k_hw_btcoex_enable(sc->sc_ah); ath9k_btcoex_timer_resume(sc); } static void ath_mci_cal_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload) { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); u32 payload[4] = {0, 0, 0, 0}; switch (opcode) { case MCI_GPM_BT_CAL_REQ: ath_dbg(common, ATH_DBG_MCI, "MCI received BT_CAL_REQ\n"); if (ar9003_mci_state(ah, MCI_STATE_BT, NULL) == MCI_BT_AWAKE) { ar9003_mci_state(ah, MCI_STATE_SET_BT_CAL_START, NULL); ieee80211_queue_work(sc->hw, &sc->hw_reset_work); } else ath_dbg(common, ATH_DBG_MCI, "MCI State mismatches: %d\n", ar9003_mci_state(ah, MCI_STATE_BT, NULL)); break; case MCI_GPM_BT_CAL_DONE: ath_dbg(common, ATH_DBG_MCI, "MCI received BT_CAL_DONE\n"); if (ar9003_mci_state(ah, MCI_STATE_BT, NULL) == MCI_BT_CAL) ath_dbg(common, ATH_DBG_MCI, "MCI error illegal!\n"); else ath_dbg(common, ATH_DBG_MCI, "MCI BT not in CAL state\n"); break; case MCI_GPM_BT_CAL_GRANT: ath_dbg(common, ATH_DBG_MCI, "MCI received BT_CAL_GRANT\n"); /* Send WLAN_CAL_DONE for now */ ath_dbg(common, ATH_DBG_MCI, "MCI send WLAN_CAL_DONE\n"); MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_DONE); ar9003_mci_send_message(sc->sc_ah, MCI_GPM, 0, payload, 16, false, true); break; default: ath_dbg(common, ATH_DBG_MCI, "MCI Unknown GPM CAL message\n"); break; } } static void ath_mci_process_profile(struct ath_softc *sc, struct ath_mci_profile_info *info) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_btcoex *btcoex = &sc->btcoex; struct ath_mci_profile *mci = &btcoex->mci; if (info->start) { if (!ath_mci_add_profile(common, mci, info)) return; } else ath_mci_del_profile(common, mci, info); btcoex->btcoex_period = ATH_MCI_DEF_BT_PERIOD; mci->aggr_limit = mci->num_sco ? 6 : 0; if (NUM_PROF(mci)) { btcoex->bt_stomp_type = ATH_BTCOEX_STOMP_LOW; btcoex->duty_cycle = ath_mci_duty_cycle[NUM_PROF(mci)]; } else { btcoex->bt_stomp_type = mci->num_mgmt ? ATH_BTCOEX_STOMP_ALL : ATH_BTCOEX_STOMP_LOW; btcoex->duty_cycle = ATH_BTCOEX_DEF_DUTY_CYCLE; } ath_mci_update_scheme(sc); } static void ath_mci_process_status(struct ath_softc *sc, struct ath_mci_profile_status *status) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_btcoex *btcoex = &sc->btcoex; struct ath_mci_profile *mci = &btcoex->mci; struct ath_mci_profile_info info; int i = 0, old_num_mgmt = mci->num_mgmt; /* Link status type are not handled */ if (status->is_link) { ath_dbg(common, ATH_DBG_MCI, "Skip link type status update\n"); return; } memset(&info, 0, sizeof(struct ath_mci_profile_info)); info.conn_handle = status->conn_handle; if (ath_mci_find_profile(mci, &info)) { ath_dbg(common, ATH_DBG_MCI, "Skip non link state update for existing profile %d\n", status->conn_handle); return; } if (status->conn_handle >= ATH_MCI_MAX_PROFILE) { ath_dbg(common, ATH_DBG_MCI, "Ignore too many non-link update\n"); return; } if (status->is_critical) __set_bit(status->conn_handle, mci->status); else __clear_bit(status->conn_handle, mci->status); mci->num_mgmt = 0; do { if (test_bit(i, mci->status)) mci->num_mgmt++; } while (++i < ATH_MCI_MAX_PROFILE); if (old_num_mgmt != mci->num_mgmt) ath_mci_update_scheme(sc); } static void ath_mci_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload) { struct ath_hw *ah = sc->sc_ah; struct ath_mci_profile_info profile_info; struct ath_mci_profile_status profile_status; struct ath_common *common = ath9k_hw_common(sc->sc_ah); u32 version; u8 major; u8 minor; u32 seq_num; switch (opcode) { case MCI_GPM_COEX_VERSION_QUERY: ath_dbg(common, ATH_DBG_MCI, "MCI Recv GPM COEX Version Query.\n"); version = ar9003_mci_state(ah, MCI_STATE_SEND_WLAN_COEX_VERSION, NULL); break; case MCI_GPM_COEX_VERSION_RESPONSE: ath_dbg(common, ATH_DBG_MCI, "MCI Recv GPM COEX Version Response.\n"); major = *(rx_payload + MCI_GPM_COEX_B_MAJOR_VERSION); minor = *(rx_payload + MCI_GPM_COEX_B_MINOR_VERSION); ath_dbg(common, ATH_DBG_MCI, "MCI BT Coex version: %d.%d\n", major, minor); version = (major << 8) + minor; version = ar9003_mci_state(ah, MCI_STATE_SET_BT_COEX_VERSION, &version); break; case MCI_GPM_COEX_STATUS_QUERY: ath_dbg(common, ATH_DBG_MCI, "MCI Recv GPM COEX Status Query = 0x%02x.\n", *(rx_payload + MCI_GPM_COEX_B_WLAN_BITMAP)); ar9003_mci_state(ah, MCI_STATE_SEND_WLAN_CHANNELS, NULL); break; case MCI_GPM_COEX_BT_PROFILE_INFO: ath_dbg(common, ATH_DBG_MCI, "MCI Recv GPM Coex BT profile info\n"); memcpy(&profile_info, (rx_payload + MCI_GPM_COEX_B_PROFILE_TYPE), 10); if ((profile_info.type == MCI_GPM_COEX_PROFILE_UNKNOWN) || (profile_info.type >= MCI_GPM_COEX_PROFILE_MAX)) { ath_dbg(common, ATH_DBG_MCI, "illegal profile type = %d," "state = %d\n", profile_info.type, profile_info.start); break; } ath_mci_process_profile(sc, &profile_info); break; case MCI_GPM_COEX_BT_STATUS_UPDATE: profile_status.is_link = *(rx_payload + MCI_GPM_COEX_B_STATUS_TYPE); profile_status.conn_handle = *(rx_payload + MCI_GPM_COEX_B_STATUS_LINKID); profile_status.is_critical = *(rx_payload + MCI_GPM_COEX_B_STATUS_STATE); seq_num = *((u32 *)(rx_payload + 12)); ath_dbg(common, ATH_DBG_MCI, "MCI Recv GPM COEX BT_Status_Update: " "is_link=%d, linkId=%d, state=%d, SEQ=%d\n", profile_status.is_link, profile_status.conn_handle, profile_status.is_critical, seq_num); ath_mci_process_status(sc, &profile_status); break; default: ath_dbg(common, ATH_DBG_MCI, "MCI Unknown GPM COEX message = 0x%02x\n", opcode); break; } } static int ath_mci_buf_alloc(struct ath_softc *sc, struct ath_mci_buf *buf) { int error = 0; buf->bf_addr = dma_alloc_coherent(sc->dev, buf->bf_len, &buf->bf_paddr, GFP_KERNEL); if (buf->bf_addr == NULL) { error = -ENOMEM; goto fail; } return 0; fail: memset(buf, 0, sizeof(*buf)); return error; } static void ath_mci_buf_free(struct ath_softc *sc, struct ath_mci_buf *buf) { if (buf->bf_addr) { dma_free_coherent(sc->dev, buf->bf_len, buf->bf_addr, buf->bf_paddr); memset(buf, 0, sizeof(*buf)); } } int ath_mci_setup(struct ath_softc *sc) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_mci_coex *mci = &sc->mci_coex; int error = 0; mci->sched_buf.bf_len = ATH_MCI_SCHED_BUF_SIZE + ATH_MCI_GPM_BUF_SIZE; if (ath_mci_buf_alloc(sc, &mci->sched_buf)) { ath_dbg(common, ATH_DBG_FATAL, "MCI buffer alloc failed\n"); error = -ENOMEM; goto fail; } mci->sched_buf.bf_len = ATH_MCI_SCHED_BUF_SIZE; memset(mci->sched_buf.bf_addr, MCI_GPM_RSVD_PATTERN, mci->sched_buf.bf_len); mci->gpm_buf.bf_len = ATH_MCI_GPM_BUF_SIZE; mci->gpm_buf.bf_addr = (u8 *)mci->sched_buf.bf_addr + mci->sched_buf.bf_len; mci->gpm_buf.bf_paddr = mci->sched_buf.bf_paddr + mci->sched_buf.bf_len; /* initialize the buffer */ memset(mci->gpm_buf.bf_addr, MCI_GPM_RSVD_PATTERN, mci->gpm_buf.bf_len); ar9003_mci_setup(sc->sc_ah, mci->gpm_buf.bf_paddr, mci->gpm_buf.bf_addr, (mci->gpm_buf.bf_len >> 4), mci->sched_buf.bf_paddr); fail: return error; } void ath_mci_cleanup(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; struct ath_mci_coex *mci = &sc->mci_coex; /* * both schedule and gpm buffers will be released */ ath_mci_buf_free(sc, &mci->sched_buf); ar9003_mci_cleanup(ah); } void ath_mci_intr(struct ath_softc *sc) { struct ath_mci_coex *mci = &sc->mci_coex; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); u32 mci_int, mci_int_rxmsg; u32 offset, subtype, opcode; u32 *pgpm; u32 more_data = MCI_GPM_MORE; bool skip_gpm = false; ar9003_mci_get_interrupt(sc->sc_ah, &mci_int, &mci_int_rxmsg); if (ar9003_mci_state(ah, MCI_STATE_ENABLE, NULL) == 0) { ar9003_mci_state(sc->sc_ah, MCI_STATE_INIT_GPM_OFFSET, NULL); ath_dbg(common, ATH_DBG_MCI, "MCI interrupt but MCI disabled\n"); ath_dbg(common, ATH_DBG_MCI, "MCI interrupt: intr = 0x%x, intr_rxmsg = 0x%x\n", mci_int, mci_int_rxmsg); return; } if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE) { u32 payload[4] = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffff00}; /* * The following REMOTE_RESET and SYS_WAKING used to sent * only when BT wake up. Now they are always sent, as a * recovery method to reset BT MCI's RX alignment. */ ath_dbg(common, ATH_DBG_MCI, "MCI interrupt send REMOTE_RESET\n"); ar9003_mci_send_message(ah, MCI_REMOTE_RESET, 0, payload, 16, true, false); ath_dbg(common, ATH_DBG_MCI, "MCI interrupt send SYS_WAKING\n"); ar9003_mci_send_message(ah, MCI_SYS_WAKING, 0, NULL, 0, true, false); mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE; ar9003_mci_state(ah, MCI_STATE_RESET_REQ_WAKE, NULL); /* * always do this for recovery and 2G/5G toggling and LNA_TRANS */ ath_dbg(common, ATH_DBG_MCI, "MCI Set BT state to AWAKE.\n"); ar9003_mci_state(ah, MCI_STATE_SET_BT_AWAKE, NULL); } /* Processing SYS_WAKING/SYS_SLEEPING */ if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING) { mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING; if (ar9003_mci_state(ah, MCI_STATE_BT, NULL) == MCI_BT_SLEEP) { if (ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP, NULL) == MCI_BT_SLEEP) ath_dbg(common, ATH_DBG_MCI, "MCI BT stays in sleep mode\n"); else { ath_dbg(common, ATH_DBG_MCI, "MCI Set BT state to AWAKE.\n"); ar9003_mci_state(ah, MCI_STATE_SET_BT_AWAKE, NULL); } } else ath_dbg(common, ATH_DBG_MCI, "MCI BT stays in AWAKE mode.\n"); } if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING) { mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING; if (ar9003_mci_state(ah, MCI_STATE_BT, NULL) == MCI_BT_AWAKE) { if (ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP, NULL) == MCI_BT_AWAKE) ath_dbg(common, ATH_DBG_MCI, "MCI BT stays in AWAKE mode.\n"); else { ath_dbg(common, ATH_DBG_MCI, "MCI SetBT state to SLEEP\n"); ar9003_mci_state(ah, MCI_STATE_SET_BT_SLEEP, NULL); } } else ath_dbg(common, ATH_DBG_MCI, "MCI BT stays in SLEEP mode\n"); } if ((mci_int & AR_MCI_INTERRUPT_RX_INVALID_HDR) || (mci_int & AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT)) { ath_dbg(common, ATH_DBG_MCI, "MCI RX broken, skip GPM msgs\n"); ar9003_mci_state(ah, MCI_STATE_RECOVER_RX, NULL); skip_gpm = true; } if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO) { mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO; offset = ar9003_mci_state(ah, MCI_STATE_LAST_SCHD_MSG_OFFSET, NULL); } if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_GPM) { mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_GPM; while (more_data == MCI_GPM_MORE) { pgpm = mci->gpm_buf.bf_addr; offset = ar9003_mci_state(ah, MCI_STATE_NEXT_GPM_OFFSET, &more_data); if (offset == MCI_GPM_INVALID) break; pgpm += (offset >> 2); /* * The first dword is timer. * The real data starts from 2nd dword. */ subtype = MCI_GPM_TYPE(pgpm); opcode = MCI_GPM_OPCODE(pgpm); if (!skip_gpm) { if (MCI_GPM_IS_CAL_TYPE(subtype)) ath_mci_cal_msg(sc, subtype, (u8 *) pgpm); else { switch (subtype) { case MCI_GPM_COEX_AGENT: ath_mci_msg(sc, opcode, (u8 *) pgpm); break; default: break; } } } MCI_GPM_RECYCLE(pgpm); } } if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_HW_MSG_MASK) { if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL) mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL; if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_LNA_INFO) { mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_LNA_INFO; ath_dbg(common, ATH_DBG_MCI, "MCI LNA_INFO\n"); } if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_CONT_INFO) { int value_dbm = ar9003_mci_state(ah, MCI_STATE_CONT_RSSI_POWER, NULL); mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_CONT_INFO; if (ar9003_mci_state(ah, MCI_STATE_CONT_TXRX, NULL)) ath_dbg(common, ATH_DBG_MCI, "MCI CONT_INFO: " "(tx) pri = %d, pwr = %d dBm\n", ar9003_mci_state(ah, MCI_STATE_CONT_PRIORITY, NULL), value_dbm); else ath_dbg(common, ATH_DBG_MCI, "MCI CONT_INFO:" "(rx) pri = %d,pwr = %d dBm\n", ar9003_mci_state(ah, MCI_STATE_CONT_PRIORITY, NULL), value_dbm); } if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_CONT_NACK) { mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_CONT_NACK; ath_dbg(common, ATH_DBG_MCI, "MCI CONT_NACK\n"); } if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_CONT_RST) { mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_CONT_RST; ath_dbg(common, ATH_DBG_MCI, "MCI CONT_RST\n"); } } if ((mci_int & AR_MCI_INTERRUPT_RX_INVALID_HDR) || (mci_int & AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT)) mci_int &= ~(AR_MCI_INTERRUPT_RX_INVALID_HDR | AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT); if (mci_int_rxmsg & 0xfffffffe) ath_dbg(common, ATH_DBG_MCI, "MCI not processed mci_int_rxmsg = 0x%x\n", mci_int_rxmsg); }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
You can’t perform that action at this time.