ath_aux.c revision 5d2225f6bb395dbd38b87e1f0af3ce4afbca42f3
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Copyright (c) 2002-2004 Sam Leffler, Errno Consulting
* 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.
* 3. Neither the names of the above-listed copyright holders nor the names
* of any contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 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.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/ethernet.h>
#include <sys/byteorder.h>
#include <inet/wifi_ioctl.h>
#include "ath_hal.h"
#include "ath_impl.h"
static const char *acnames[] = {
"WME_AC_BE",
"WME_AC_BK",
"WME_AC_VI",
"WME_AC_VO",
"WME_UPSD"
};
const char *
{
static const char *hal_status_desc[] = {
"No error",
"No hardware present or device not yet supported",
"Memory allocation failed",
"Hardware didn't respond as expected",
"EEPROM magic number invalid",
"EEPROM version invalid",
"EEPROM unreadable",
"EEPROM checksum invalid",
"EEPROM read problem",
"EEPROM mac address invalid",
"EEPROM size not supported",
"Attempt to change write-locked EEPROM",
"Invalid parameter to function",
"Hardware revision not supported",
"Hardware self-test failed",
"Operation incomplete"
};
return (hal_status_desc[status]);
else
return ("");
}
{
return (rfilt);
}
static int
{
int qnum;
"ac %u out of range, max %u!\n",
return (1);
}
/*
* Enable interrupts only for EOL and DESC conditions.
* We mark tx descriptors to receive a DESC interrupt
* when a tx queue gets deep; otherwise waiting for the
* EOL to reap descriptors. Note that this is done to
* reduce interrupt load and this only defers reaping
* descriptors, never transmitting frames. Aside from
* reducing interrupts this also permits more concurrency.
* The only potential downside is if the tx queue backs
* up in which case the top half of the kernel may backup
* due to a lack of tx descriptors.
*/
if (qnum == -1) {
"Unable to setup hardware queue for %s traffic!\n",
return (1);
}
"hal qnum %u out of range, max %u!\n",
return (1);
}
txq->axq_intrcnt = 0;
}
return (0);
}
int
{
return (1);
}
return (0);
}
void
{
int i;
for (i = 0; i < HAL_NUM_TX_QUEUES; i++) {
if (ATH_TXQ_SETUP(asc, i)) {
}
}
}
void
{
const HAL_RATE_TABLE *rt;
int i;
for (i = 0; i < sizeof (asc->asc_rixmap); i++)
(uint8_t)i;
}
/* Set correct parameters for a certain mode */
void
{
/* configure rx filter */
"mode =%d RX filter 0x%x, MC filter %08x:%08x\n",
}
/*
* Disable the receive h/w in preparation for a reset.
*/
void
{
drv_usecwait(3000);
}
{
0, /* IEEE80211_MODE_AUTO */
CHANNEL_A, /* IEEE80211_MODE_11A */
CHANNEL_B, /* IEEE80211_MODE_11B */
CHANNEL_PUREG, /* IEEE80211_MODE_11G */
0, /* IEEE80211_MODE_FH */
CHANNEL_108A, /* IEEE80211_MODE_TURBO_A */
CHANNEL_108G /* IEEE80211_MODE_TURBO_G */
};
}
int
{
int i, ix;
chans = (HAL_CHANNEL *)
"unable to get channel list\n"));
return (EINVAL);
}
/*
* Convert HAL channels to ieee80211 ones and insert
* them in the table according to their channel number.
*/
for (i = 0; i < nchan; i++) {
HAL_CHANNEL *c = &chans[i];
if (ix > IEEE80211_CHAN_MAX) {
"bad hal channel %d (%u/%x) ignored\n",
continue;
}
/* NB: flags are known to be compatible */
if (ix < 0) {
/*
* can't handle frequency <2400MHz (negative
* channels) right now
*/
"hal channel %d (%u/%x) "
"cannot be handled, ignored\n",
continue;
}
/*
* Calculate net80211 flags; most are compatible
* but some need massaging. Note the static turbo
* conversion can be removed once net80211 is updated
* to understand static vs. dynamic turbo.
*/
if (c->channelFlags & CHANNEL_STURBO)
} else {
/* channels overlap; e.g. 11g and 11b */
}
}
return (0);
}
static void
{
/*
* This assumes output has been stopped.
*/
for (;;) {
break;
}
}
}
/*
* Drain the transmit queues and reclaim resources.
*/
void
{
int i;
if (!asc->asc_invalid) {
for (i = 0; i < HAL_NUM_TX_QUEUES; i++) {
if (ATH_TXQ_SETUP(asc, i)) {
}
}
}
for (i = 0; i < HAL_NUM_TX_QUEUES; i++) {
if (ATH_TXQ_SETUP(asc, i)) {
}
}
}
/* Enable the receive h/w following a reset */
int
{
}
return (0);
}
/*
* Update internal state after a channel change.
*/
void
{
enum ieee80211_phymode mode;
/*
* Change channels and update the h/w rate map
* if we're switching; e.g. 11a to 11b/g.
*/
}
/*
* it's done by resetting the chip. To accomplish this we must
* first cleanup any pending DMA.
*/
int
{
/*
* To switch channels clear any pending DMA operations;
* wait long enough for the RX fifo to drain, reset the
* hardware at the new frequency, and then re-enable
* the relevant bits of the h/w.
*/
/*
* Convert to a HAL channel description with
* the flags constrained to reflect the current
* operating mode.
*/
"unable to reset channel %u (%uMhz)\n"
"flags 0x%x: '%s' (HAL status %u)\n",
return (EIO);
}
/*
* Re-enable rx framework.
*/
if (ath_startrecv(asc) != 0) {
ath_problem("ath: ath_chan_set(): "
"restarting receiving logic failed\n");
return (EIO);
}
/*
* Change channels and update the h/w rate map
* if we're switching; e.g. 11a to 11b/g.
*/
/*
* Re-enable interrupts.
*/
}
return (0);
}
/*
* Configure the beacon and sleep timers.
*
* When operating as an AP this resets the TSF and sets
* up the hardware to notify us when we need to issue beacons.
*
* When operating in station mode this sets up the beacon
* timers according to the timestamp of the last received
* beacon and the current TSF, configures PCF and DTIM
* handling, programs the sleep registers so the hardware
* will wakeup in time to receive beacons, and configures
* the beacon miss handling so we'll receive a BMISS
* interrupt when we stop seeing beacons from the AP
* we've associated with.
*/
void
{
/* NB: no PCF support right now */
/*
* Setup the number of consecutive beacons to miss
* before taking a BMISS interrupt.
* Note that we clamp the result to at most 10 beacons.
*/
/*
* Calculate sleep duration. The configuration is
* given in ms. We insure a multiple of the beacon
* period is used. Also, if the sleep duration is
* greater than the DTIM period then it makes senses
* to make it a multiple of that.
*/
"intval %u nexttbtt %u dtim %u"
" nextdtim %u bmiss %u sleep %u\n",
ATH_HAL_INTRSET(ah, 0);
/*
* Reset our tsf so the hardware will update the
* tsf register to reflect timestamps found in
* received beacons.
*/
} else {
ATH_HAL_INTRSET(ah, 0);
}
}
/*
*/
static int
{
if (b != 0xff) {
/*
* One or more slots in this byte are free.
*/
while (b & 1) {
keyix++;
b >>= 1;
}
/* XXX IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV */
/* full pair unavailable */
/* no slots were appropriate, advance */
continue;
}
goto again;
}
"key_alloc_2pair: key pair %u,%u %u,%u\n",
return (1);
}
}
" out of pair space\n"));
return (0);
}
/*
* Allocate a single key cache slot.
*/
static int
{
/* try i,i+32,i+64,i+32+64 to minimize key pair conflicts */
if (b != 0xff) {
/*
* One or more slots are free.
*/
while (b & 1)
keyix++, b >>= 1;
" key %u\n", keyix));
return (1);
}
}
return (0);
}
/*
* Allocate one or more key cache slots for a unicast key. The
* key itself is needed only to identify the cipher. For hardware
* TKIP with split cipher+MIC keys we allocate two key cache slot
* pairs so that we can setup separate TX and RX MIC keys. Note
* that the MIC key for a TKIP key at slot i is assumed by the
* hardware to be at slot i+64. This limits TKIP keys to the first
* 64 entries.
*/
/* ARGSUSED */
int
{
/*
* We allocate two pair for TKIP when using the h/w to do
* the MIC. For everything else, including software crypto,
* we allocate a single entry. Note that s/w crypto requires
* a pass-through slot on the 5211 and 5212. The 5210 does
* not support pass-through cache entries and we map all
* those requests to slot 0.
*/
if (k->wk_flags & IEEE80211_KEY_SWCRYPT) {
} else {
}
}
/*
* Delete an entry in the key cache allocated by ath_key_alloc.
*/
int
{
/*
*/
if (keyix >= IEEE80211_WEP_NKID) {
/*
* Don't touch keymap entries for global keys so
* they are never considered for dynamic allocation.
*/
(k->wk_flags & IEEE80211_KEY_SWMIC) == 0 &&
asc->asc_splitmic) {
}
}
return (1);
}
static void
{
static const char *ciphers[] = {
"WEP",
"AES-OCB",
"AES-CCM",
"CKIP",
"TKIP",
"CLR",
};
int i, n;
}
}
}
}
/*
* Set a TKIP key into the hardware. This handles the
* potential distribution of key state to multiple key
* cache slots for TKIP.
*/
static int
{
/*
* TX key goes at first index, RX key at +32.
* The hal handles the MIC keys at index+64.
*/
return (0);
} else if (k->wk_flags & IEEE80211_KEY_XR) {
/*
* The hal handles the MIC keys are index+64.
*/
}
return (0);
}
/*
* Set the key cache contents for the specified key. Key cache
* slot(s) must already have been allocated by ath_key_alloc.
*/
int
{
HAL_CIPHER_WEP, /* IEEE80211_CIPHER_WEP */
HAL_CIPHER_TKIP, /* IEEE80211_CIPHER_TKIP */
HAL_CIPHER_AES_OCB, /* IEEE80211_CIPHER_AES_OCB */
HAL_CIPHER_AES_CCM, /* IEEE80211_CIPHER_AES_CCM */
HAL_CIPHER_CKIP, /* IEEE80211_CIPHER_CKIP */
HAL_CIPHER_CLR, /* IEEE80211_CIPHER_NONE */
};
/*
* Software crypto uses a "clear key" so non-crypto
* state kept in the key cache are maintainedd so that
* rx frames have an entry to match.
*/
if ((k->wk_flags & IEEE80211_KEY_SWCRYPT) == 0) {
} else {
}
(k->wk_flags & IEEE80211_KEY_SWMIC) == 0 &&
asc->asc_splitmic) {
} else {
}
}
/*
*/
void
{
if (onoff)
else
}
int
{
struct ieee80211_channel *ch;
/*
* Convert to a HAL channel description with the flags
* constrained to reflect the current operating mode.
*/
if (ATH_IS_RUNNING(asc)) {
/* indicate channel change so we do a full reset */
ath_problem("ath: ath_reset(): "
"resetting hardware failed, '%s' (HAL status %u)\n",
}
}
if (ATH_IS_RUNNING(asc)) {
ath_problem("ath: ath_reset(): "
"starting receiving logic failed\n");
}
}
return (0);
}