diff --git a/sys/conf/files b/sys/conf/files index fa1206839358..266c6f063a4c 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -725,6 +725,8 @@ dev/ath/if_ath.c optional ath \ compile-with "${NORMAL_C} -I$S/dev/ath" dev/ath/if_ath_beacon.c optional ath \ compile-with "${NORMAL_C} -I$S/dev/ath" +dev/ath/if_ath_btcoex.c optional ath \ + compile-with "${NORMAL_C} -I$S/dev/ath" dev/ath/if_ath_debug.c optional ath \ compile-with "${NORMAL_C} -I$S/dev/ath" dev/ath/if_ath_keycache.c optional ath \ diff --git a/sys/dev/ath/if_ath.c b/sys/dev/ath/if_ath.c index 757ee6fe417e..91c5bf652090 100644 --- a/sys/dev/ath/if_ath.c +++ b/sys/dev/ath/if_ath.c @@ -111,6 +111,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -521,6 +522,14 @@ ath_attach(u_int16_t devid, struct ath_softc *sc) goto bad2; } + /* Attach bluetooth coexistence module */ + if (ath_btcoex_attach(sc) < 0) { + device_printf(sc->sc_dev, + "%s: unable to attach bluetooth coexistence\n", __func__); + error = EIO; + goto bad2; + } + /* Start DFS processing tasklet */ TASK_INIT(&sc->sc_dfstask, 0, ath_dfs_tasklet, sc); @@ -1029,6 +1038,7 @@ ath_detach(struct ath_softc *sc) #ifdef ATH_DEBUG_ALQ if_ath_alq_tidyup(&sc->sc_alq); #endif + ath_btcoex_detach(sc); ath_spectral_detach(sc); ath_dfs_detach(sc); ath_desc_free(sc); @@ -1588,6 +1598,11 @@ ath_resume(struct ath_softc *sc) /* Let spectral at in case spectral is enabled */ ath_spectral_enable(sc, ic->ic_curchan); + /* + * Let bluetooth coexistence at in case it's needed for this channel + */ + ath_btcoex_enable(sc, ic->ic_curchan); + /* * If we're doing TDMA, enforce the TXOP limitation for chips that * support it. @@ -2044,6 +2059,11 @@ ath_init(void *arg) /* Let spectral at in case spectral is enabled */ ath_spectral_enable(sc, ic->ic_curchan); + /* + * Let bluetooth coexistence at in case it's needed for this channel + */ + ath_btcoex_enable(sc, ic->ic_curchan); + /* * If we're doing TDMA, enforce the TXOP limitation for chips that * support it. @@ -2383,6 +2403,11 @@ ath_reset(struct ifnet *ifp, ATH_RESET_TYPE reset_type) /* Let spectral at in case spectral is enabled */ ath_spectral_enable(sc, ic->ic_curchan); + /* + * Let bluetooth coexistence at in case it's needed for this channel + */ + ath_btcoex_enable(sc, ic->ic_curchan); + /* * If we're doing TDMA, enforce the TXOP limitation for chips that * support it. @@ -4945,6 +4970,12 @@ ath_chan_set(struct ath_softc *sc, struct ieee80211_channel *chan) /* Let spectral at in case spectral is enabled */ ath_spectral_enable(sc, chan); + /* + * Let bluetooth coexistence at in case it's needed for this + * channel + */ + ath_btcoex_enable(sc, ic->ic_curchan); + /* * If we're doing TDMA, enforce the TXOP limitation for chips * that support it. diff --git a/sys/dev/ath/if_ath_btcoex.c b/sys/dev/ath/if_ath_btcoex.c new file mode 100644 index 000000000000..ef9073d2c19a --- /dev/null +++ b/sys/dev/ath/if_ath_btcoex.c @@ -0,0 +1,281 @@ +/*- + * Copyright (c) 2013 Adrian Chadd + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + * $FreeBSD$ + */ +#include +__FBSDID("$FreeBSD$"); + +/* + * This implements some very basic bluetooth coexistence methods for + * the ath(4) hardware. + */ +#include "opt_ath.h" +#include "opt_inet.h" +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include /* XXX for ether_sprintf */ + +#include + +#include + +#ifdef INET +#include +#include +#endif + +#include +#include + +/* + * Initial AR9285 / (WB195) bluetooth coexistence settings, + * just for experimentation. + * + * Return 0 for OK; errno for error. + * + * XXX TODO: There needs to be a PCIe workaround to disable ASPM if + * bluetooth coexistence is enabled. + */ +static int +ath_btcoex_cfg_wb195(struct ath_softc *sc) +{ + HAL_BT_COEX_INFO btinfo; + HAL_BT_COEX_CONFIG btconfig; + struct ath_hal *ah = sc->sc_ah; + + if (! ath_hal_btcoex_supported(ah)) + return (EINVAL); + + bzero(&btinfo, sizeof(btinfo)); + bzero(&btconfig, sizeof(btconfig)); + + device_printf(sc->sc_dev, "Enabling WB195 BTCOEX\n"); + + btinfo.bt_module = HAL_BT_MODULE_JANUS; + btinfo.bt_coex_config = HAL_BT_COEX_CFG_3WIRE; + /* + * These are the three GPIO pins hooked up between the AR9285 and + * the AR3011. + */ + btinfo.bt_gpio_bt_active = 6; + btinfo.bt_gpio_bt_priority = 7; + btinfo.bt_gpio_wlan_active = 5; + btinfo.bt_active_polarity = 1; /* XXX not used */ + btinfo.bt_single_ant = 1; /* 1 antenna on ar9285 ? */ + btinfo.bt_isolation = 0; /* in dB, not used */ + + ath_hal_btcoex_set_info(ah, &btinfo); + + btconfig.bt_time_extend = 0; + btconfig.bt_txstate_extend = 1; /* true */ + btconfig.bt_txframe_extend = 1; /* true */ + btconfig.bt_mode = HAL_BT_COEX_MODE_SLOTTED; + btconfig.bt_quiet_collision = 1; /* true */ + btconfig.bt_rxclear_polarity = 1; /* true */ + btconfig.bt_priority_time = 2; + btconfig.bt_first_slot_time = 5; + btconfig.bt_hold_rxclear = 1; /* true */ + + ath_hal_btcoex_set_config(ah, &btconfig); + + /* + * Enable antenna diversity. + */ + ath_hal_btcoex_set_parameter(ah, HAL_BT_COEX_ANTENNA_DIVERSITY, 1); + + return (0); +} + +#if 0 +/* + * When using bluetooth coexistence, ASPM needs to be disabled + * otherwise the sleeping interferes with the bluetooth (USB) + * operation and the MAC sleep/wakeup hardware. + */ +static int +ath_btcoex_aspm_wb195(struct ath_softc *sc) +{ + + /* XXX TODO: clear device ASPM L0S and L1 */ + /* XXX TODO: clear _parent_ ASPM L0S and L1 */ +} +#endif + +/* + * Methods which are required + */ + +/* + * Attach btcoex to the given interface + */ +int +ath_btcoex_attach(struct ath_softc *sc) +{ + int ret; + struct ath_hal *ah = sc->sc_ah; + const char *profname; + + /* + * No chipset bluetooth coexistence? Then do nothing. + */ + if (! ath_hal_btcoex_supported(ah)) + return (0); + + /* + * Look at the hints to determine which bluetooth + * profile to configure. + */ + ret = resource_string_value(device_get_name(sc->sc_dev), + device_get_unit(sc->sc_dev), + "btcoex_profile", + &profname); + if (ret != 0) { + /* nothing to do */ + return (0); + } + + if (strncmp(profname, "wb195", 5) == 0) { + ret = ath_btcoex_cfg_wb195(sc); + } else { + return (0); + } + + /* + * Propagate up failure from the actual attach phase. + */ + if (ret != 0) + return (ret); + + return (0); +} + +/* + * Detach btcoex from the given interface + */ +int +ath_btcoex_detach(struct ath_softc *sc) +{ + + return (0); +} + +/* + * Configure or disable bluetooth coexistence on the given channel. + * + * For AR9285/AR9287/AR9485, we'll never see a 5GHz channel, so we just + * assume bluetooth coexistence is always on. + * + * For AR9462, we may see a 5GHz channel; bluetooth coexistence should + * not be enabled on those channels. + */ +int +ath_btcoex_enable(struct ath_softc *sc, const struct ieee80211_channel *chan) +{ + + return (0); +} + +/* + * Handle ioctl requests from the diagnostic interface. + * + * The initial part of this code resembles ath_ioctl_diag(); + * it's likely a good idea to reduce duplication between + * these two routines. + */ +int +ath_btcoex_ioctl(struct ath_softc *sc, struct ath_diag *ad) +{ + unsigned int id = ad->ad_id & ATH_DIAG_ID; + void *indata = NULL; + void *outdata = NULL; + u_int32_t insize = ad->ad_in_size; + u_int32_t outsize = ad->ad_out_size; + int error = 0; +// int val; + + if (ad->ad_id & ATH_DIAG_IN) { + /* + * Copy in data. + */ + indata = malloc(insize, M_TEMP, M_NOWAIT); + if (indata == NULL) { + error = ENOMEM; + goto bad; + } + error = copyin(ad->ad_in_data, indata, insize); + if (error) + goto bad; + } + if (ad->ad_id & ATH_DIAG_DYN) { + /* + * Allocate a buffer for the results (otherwise the HAL + * returns a pointer to a buffer where we can read the + * results). Note that we depend on the HAL leaving this + * pointer for us to use below in reclaiming the buffer; + * may want to be more defensive. + */ + outdata = malloc(outsize, M_TEMP, M_NOWAIT); + if (outdata == NULL) { + error = ENOMEM; + goto bad; + } + } + switch (id) { + default: + error = EINVAL; + } + if (outsize < ad->ad_out_size) + ad->ad_out_size = outsize; + if (outdata && copyout(outdata, ad->ad_out_data, ad->ad_out_size)) + error = EFAULT; +bad: + if ((ad->ad_id & ATH_DIAG_IN) && indata != NULL) + free(indata, M_TEMP); + if ((ad->ad_id & ATH_DIAG_DYN) && outdata != NULL) + free(outdata, M_TEMP); + return (error); +} + diff --git a/sys/dev/ath/if_ath_btcoex.h b/sys/dev/ath/if_ath_btcoex.h new file mode 100644 index 000000000000..8b175d257d49 --- /dev/null +++ b/sys/dev/ath/if_ath_btcoex.h @@ -0,0 +1,40 @@ +/*- + * Copyright (c) 2013 Adrian Chadd + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + * $FreeBSD$ + */ +#ifndef __IF_ATH_BTCOEX_H__ +#define __IF_ATH_BTCOEX_H__ + +extern int ath_btcoex_attach(struct ath_softc *sc); +extern int ath_btcoex_detach(struct ath_softc *sc); +extern int ath_btcoex_ioctl(struct ath_softc *sc, struct ath_diag *ad); +extern int ath_btcoex_enable(struct ath_softc *sc, + const struct ieee80211_channel *ch); + +#endif /* __IF_ATH_BTCOEX_H__ */ diff --git a/sys/modules/ath/Makefile b/sys/modules/ath/Makefile index 5de861f11948..1ae849f2a717 100644 --- a/sys/modules/ath/Makefile +++ b/sys/modules/ath/Makefile @@ -38,6 +38,7 @@ KMOD= if_ath SRCS= if_ath.c if_ath_alq.c if_ath_debug.c if_ath_keycache.c if_ath_sysctl.c SRCS+= if_ath_tx.c if_ath_tx_ht.c if_ath_led.c if_ath_rx.c if_ath_tdma.c SRCS+= if_ath_beacon.c if_ath_rx_edma.c if_ath_tx_edma.c if_ath_spectral.c +SRCS+= if_ath_btcoex.c # NB: v3 eeprom support used by both AR5211 and AR5212; just include it SRCS+= ah_osdep.c ah.c ah_regdomain.c ah_eeprom_v3.c SRCS+= device_if.h bus_if.h pci_if.h opt_inet.h opt_ath.h opt_ah.h opt_wlan.h