ath_main.c revision cd5560ef29d7a0451b9a7ab81863515641f482b6
/*
* Copyright 2007 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"
/*
* Driver for the Atheros Wireless LAN controller.
*
* The Atheros driver calls into net80211 module for IEEE80211 protocol
* management functionalities. The driver includes a LLD(Low Level Driver)
* part to implement H/W related operations.
* The following is the high level structure of ath driver.
* (The arrows between modules indicate function call direction.)
*
*
* |
* | GLD thread
* V
* ================== =========================================
* | | |[1] |
* | | | GLDv3 Callback functions registered |
* | Net80211 | ========================= by |
* | module | | | driver |
* | | V | |
* | |======================== | |
* | Functions exported by net80211 | | |
* | | | |
* ========================================== =================
* | |
* V |
* +----------------------------------+ |
* |[2] | |
* | Net80211 Callback functions | |
* | registered by LLD | |
* +----------------------------------+ |
* | |
* V v
* +-----------------------------------------------------------+
* |[3] |
* | LLD Internal functions |
* | |
* +-----------------------------------------------------------+
* ^
* | Software interrupt thread
* |
*
* The short description of each module is as below:
* Module 1: GLD callback functions, which are intercepting the calls from
* GLD to LLD.
* Module 2: Net80211 callback functions registered by LLD, which
* calls into LLD for H/W related functions needed by net80211.
* Module 3: LLD Internal functions, which are responsible for allocing
* descriptor/buffer, handling interrupt and other H/W
* operations.
*
* All functions are running in 3 types of thread:
* 1. GLD callbacks threads, such as ioctl, intr, etc.
* 2. Clock interruptt thread which is responsible for scan, rate control and
* calibration.
* 3. Software Interrupt thread originated in LLD.
*
* The lock strategy is as below:
* There have 4 queues for tx, each queue has one asc_txqlock[i] to
* prevent conflicts access to queue resource from different thread.
*
* All the transmit buffers are contained in asc_txbuf which are
* protected by asc_txbuflock.
*
* Each receive buffers are contained in asc_rxbuf which are protected
* by asc_rxbuflock.
*
* In ath struct, asc_genlock is a general lock, protecting most other
* operational data in ath_softc struct and HAL accesses.
* It is acquired by the interupt handler and most "mode-ctrl" routines.
*
* Any of the locks can be acquired singly, but where multiple
* locks are acquired, they *must* be in the order:
* asc_genlock >> asc_txqlock[i] >> asc_txbuflock >> asc_rxbuflock
*/
#include <sys/ethernet.h>
#include <sys/byteorder.h>
#include <inet/wifi_ioctl.h>
#include <sys/mac_wifi.h>
#include "ath_hal.h"
#include "ath_impl.h"
#include "ath_aux.h"
#include "ath_rate.h"
extern void ath_halfix_init(void);
extern void ath_halfix_finit(void);
/*
* PIO access attributes for registers
*/
static ddi_device_acc_attr_t ath_reg_accattr = {
};
/*
* DMA access attributes for descriptors: NOT to be byte swapped.
*/
static ddi_device_acc_attr_t ath_desc_accattr = {
};
/*
* Describes the chip's DMA engine
*/
static ddi_dma_attr_t dma_attr = {
DMA_ATTR_V0, /* dma_attr version */
0x0000000000000000ull, /* dma_attr_addr_lo */
0xFFFFFFFFFFFFFFFFull, /* dma_attr_addr_hi */
0x00000000FFFFFFFFull, /* dma_attr_count_max */
0x0000000000000001ull, /* dma_attr_align */
0x00000FFF, /* dma_attr_burstsizes */
0x00000001, /* dma_attr_minxfer */
0x000000000000FFFFull, /* dma_attr_maxxfer */
0xFFFFFFFFFFFFFFFFull, /* dma_attr_seg */
1, /* dma_attr_sgllen */
0x00000001, /* dma_attr_granular */
0 /* dma_attr_flags */
};
static kmutex_t ath_loglock;
static void *ath_soft_state_p = NULL;
static int ath_m_start(void *);
static void ath_m_stop(void *);
static int ath_m_promisc(void *, boolean_t);
static int ath_m_unicst(void *, const uint8_t *);
static mac_callbacks_t ath_m_callbacks = {
NULL, /* mc_resources; */
NULL /* mc_getcapab */
};
/*
* Available debug flags:
* ATH_DBG_INIT, ATH_DBG_GLD, ATH_DBG_HAL, ATH_DBG_INT, ATH_DBG_ATTACH,
* ATH_DBG_DETACH, ATH_DBG_AUX, ATH_DBG_WIFICFG, ATH_DBG_OSDEP
*/
uint32_t ath_dbg_flags = 0;
/*
*/
void
{
}
/*
* Normal log information independent of debug.
*/
void
{
}
void
{
if (dbg_flags & ath_dbg_flags) {
}
}
void
{
0);
}
/*
* Allocate an area of memory and a DMA handle for accessing it
*/
static int
{
int err;
/*
* Allocate handle
*/
if (err != DDI_SUCCESS)
return (DDI_FAILURE);
/*
* Allocate memory
*/
if (err != DDI_SUCCESS)
return (DDI_FAILURE);
/*
* Bind the two together
*/
if (err != DDI_DMA_MAPPED)
return (DDI_FAILURE);
return (DDI_SUCCESS);
}
/*
* Free one allocated area of DMAable memory
*/
static void
{
}
}
}
static int
{
int i, err;
&asc->asc_desc_dma);
/* virtual address of the first descriptor */
"%p (%d) -> %p\n",
/* create RX buffer list and allocate DMA memory */
/* alloc DMA memory */
if (err != DDI_SUCCESS)
return (err);
}
/* create TX buffer list and allocate DMA memory */
/* alloc DMA memory */
if (err != DDI_SUCCESS)
return (err);
}
return (DDI_SUCCESS);
}
static void
{
/* Free TX DMA buffer */
}
/* Free RX DMA uffer */
}
/* Free descriptor DMA buffer */
}
static void
{
"%08x %08x %08x %c\n",
}
static void
{
struct ieee80211_frame *wh;
struct ieee80211_node *in;
do {
"no buffer\n"));
break;
}
/*
* Never process the self-linked entry at the end,
* this may be met at heavy load.
*/
break;
}
if (status == HAL_EINPROGRESS) {
break;
}
}
goto rx_next;
}
/* less than sizeof(struct ieee80211_frame) */
if (len < 20) {
goto rx_next;
}
ath_problem("ath: ath_rx_handler(): "
"allocing mblk buffer failed.\n");
return;
}
/*
* Ignore control frame received in promisc mode.
*/
goto rx_next;
}
/* Remove the CRC at the end of IEEE80211 frame */
#ifdef DEBUG
#endif /* DEBUG */
/*
* Locate the node for sender, track state, and then
* pass the (referenced) node up to the 802.11 layer
* for its use.
*/
/*
* Send frame up for processing.
*/
} while (loop);
/* rx signal state monitoring */
}
static void
{
" %08x %08x %08x %c\n",
}
/*
* The input parameter mp has following assumption:
* For data packets, GLDv3 mac_wifi plugin allocates and fills the
* ieee80211 header. For management packets, net80211 allocates and
* fills the ieee80211 header. In both cases, enough spaces in the
* header are left for encryption option.
*/
static int32_t
{
struct ieee80211_frame *wh;
const HAL_RATE_TABLE *rt;
/*
* CRC are added by H/W, not encaped by driver,
* but we must count it in pkt length.
*/
hdrlen = sizeof (struct ieee80211_frame);
if (iswep != 0) {
const struct ieee80211_cipher *cip;
struct ieee80211_key *k;
/*
* Construct the 802.11 header+trailer for an encrypted
* frame. The only reason this can fail is because of an
*/
if (k == NULL) {
/*
* This can happen when the key is yanked after the
* frame was queued. Just discard the frame; the
* 802.11 layer counts failures and provides
*/
return (EIO);
}
/*
* Adjust the packet + header lengths for the crypto
* additions and calculate the h/w key index. When
* a s/w mic is done the frame will have had any mic
* added to it prior to entry so m0->m_pkthdr.len above will
* account for it. Otherwise we need to add it to the
* packet length.
*/
if ((k->wk_flags & IEEE80211_KEY_SWMIC) == 0)
/* packet header may have moved, reset our local pointer */
}
}
/* setup descriptors */
/*
* The 802.11 layer marks whether or not we should
* use short preamble based on the current mode and
* negotiated parameters.
*/
} else {
}
/*
* Calculate Atheros packet type from IEEE80211 packet header
* and setup for rate calculations.
*/
case IEEE80211_FC0_TYPE_MGT:
if (subtype == IEEE80211_FC0_SUBTYPE_BEACON)
else if (subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP)
else if (subtype == IEEE80211_FC0_SUBTYPE_ATIM)
else
rix = 0; /* lowest rate */
try0 = ATH_TXMAXTRY;
if (shortPreamble)
else
/* force all ctl frames to highest queue */
break;
case IEEE80211_FC0_TYPE_CTL:
rix = 0; /* lowest rate */
try0 = ATH_TXMAXTRY;
if (shortPreamble)
else
/* force all ctl frames to highest queue */
break;
case IEEE80211_FC0_TYPE_DATA:
if (shortPreamble)
else
/* Always use background queue */
break;
default:
/* Unknown 802.11 frame */
return (1);
}
/*
* Calculate miscellaneous flags.
*/
}
/*
* Calculate duration. This logically belongs in the 802.11
* layer but it lacks sufficient information to calculate it.
*/
if ((flags & HAL_TXDESC_NOACK) == 0 &&
rix, shortPreamble);
}
/*
*/
ctsduration = 0;
/*
* CTS transmit rate is derived from the transmit rate
* by looking in the h/w rate table. We must also factor
* in whether or not a short preamble is to be used.
*/
if (shortPreamble)
/*
* Compute the transmit duration based on the size
* of an ACK frame. We call into the HAL to do the
* computation since it depends on the characteristics
* of the actual PHY being used.
*/
}
/* SIFS + data */
}
} else
ctsrate = 0;
txq->axq_intrcnt = 0;
}
/*
* Formulate first tx descriptor with tx controls.
*/
pktlen, /* packet length */
hdrlen, /* header length */
atype, /* Atheros packet type */
keyix, /* key cache index */
flags, /* flags */
ctsduration); /* rts/cts duration */
"an->an_tx_rate1sp=%d tx_rate2sp=%d tx_rate3sp=%d "
"qnum=%d rix=%d sht=%d dur = %d\n",
/*
* Setup the multi-rate retry state only when we're
* going to use it. This assumes ath_hal_setuptxdesc
* initializes the descriptors (so we don't have to)
* when the hardware supports multi-rate retry and
* we don't use it.
*/
if (try0 != ATH_TXMAXTRY)
mbslen, /* segment length */
AH_TRUE, /* first segment */
AH_TRUE, /* last segment */
ds); /* first descriptor */
} else {
}
return (0);
}
/*
* Transmit a management frame. On failure we reclaim the skbuff.
* Note that management frames come directly from the 802.11 layer
* and do not honor the send queue flow control. Need to investigate
* using priority queueing so management frames can bypass data.
*/
static int
{
struct ieee80211_frame *wh;
int error = 0;
/* Grab a TX buffer */
"stop queue\n"));
}
"no xmit buf\n"));
if ((type & IEEE80211_FC0_TYPE_MASK) ==
} else {
}
return (ENOMEM);
}
/* Locate node */
goto bad;
}
switch (type & IEEE80211_FC0_TYPE_MASK) {
case IEEE80211_FC0_TYPE_DATA:
break;
default:
/* fill time stamp */
/* adjust 100us delay to xmit */
tsf += 100;
}
break;
}
if (error != 0) {
bad:
}
}
error == 0) {
}
return (error);
}
static mblk_t *
{
/*
* No data frames go out unless we're associated; this
* should not happen as the 802.11 layer does not enable
* the xmit queue until we enter the RUN state.
*/
return (NULL);
}
break;
}
}
return (mp);
}
static int
{
struct ieee80211_node *in;
for (;;) {
break;
}
#ifdef DEBUG
#endif
if (status == HAL_EINPROGRESS) {
break;
}
/* Successful transmition */
an->an_tx_antenna =
} else {
}
/*
* Hand the descriptor to the rate control algorithm.
*/
/*
* If frame was ack'd update the last rx time
* used to workaround phantom bmiss interrupts.
*/
nacked++;
} else {
}
}
}
/*
* Reschedule stalled outbound packets
*/
if (asc->asc_resched_needed) {
}
}
return (nacked);
}
static void
{
int i;
/*
* Process each active queue.
*/
for (i = 0; i < HAL_NUM_TX_QUEUES; i++) {
if (ATH_TXQ_SETUP(asc, i)) {
}
}
}
static struct ieee80211_node *
{
}
static void
{
int32_t i;
for (i = 0; i < HAL_NUM_TX_QUEUES; i++) {
if (ATH_TXQ_SETUP(asc, i)) {
}
}
}
}
}
static void
ath_next_scan(void *arg)
{
asc->asc_scan_timer = 0;
}
}
static void
{
timeout_id_t tmp_id = 0;
}
asc->asc_scan_timer = 0;
}
static int32_t
{
struct ieee80211_node *in;
enum ieee80211_state ostate;
static const HAL_LED_STATE leds[] = {
HAL_LED_INIT, /* IEEE80211_S_INIT */
HAL_LED_SCAN, /* IEEE80211_S_SCAN */
HAL_LED_AUTH, /* IEEE80211_S_AUTH */
HAL_LED_ASSOC, /* IEEE80211_S_ASSOC */
HAL_LED_RUN, /* IEEE80211_S_RUN */
};
if (!ATH_IS_RUNNING(asc))
return (0);
if (nstate != IEEE80211_S_SCAN)
if (nstate == IEEE80211_S_INIT) {
goto done;
}
if (error != 0) {
if (nstate != IEEE80211_S_SCAN) {
goto bad;
}
}
if (nstate == IEEE80211_S_SCAN)
else
else
for (i = 0; i < IEEE80211_WEP_NKID; i++) {
if (ATH_HAL_KEYISVALID(ah, i))
}
}
if ((nstate == IEEE80211_S_RUN) &&
(ostate != IEEE80211_S_RUN)) {
/* Configure the beacon and sleep timers. */
} else {
}
/*
* Reset the rate control state.
*/
char *str_name = "ATH";
char str_value[256] = {0};
"ic_flags=0x%08x iv=%d"
" bssid=%s capinfo=0x%04x chan=%d\n",
in->in_capinfo,
if (nvlist_alloc(&attr_list,
NV_UNIQUE_NAME_TYPE, KM_SLEEP) == 0) {
if (err != DDI_SUCCESS)
"ath_new_state: error log event\n"));
DDI_VENDOR_SUNW, "class",
"subclass", attr_list,
&eid, DDI_NOSLEEP);
if (err != DDI_SUCCESS)
"ath_new_state(): error log event\n"));
}
}
done:
/*
* Invoke the parent method to complete the work.
*/
/*
* Finally, start any timers.
*/
if (nstate == IEEE80211_S_RUN) {
}
bad:
return (error);
}
/*
* Periodically recalibrate the PHY to account
* for temperature/environment changes.
*/
static void
{
/*
* Rfgain is out of bounds, reset the chip
* to load new gain values.
*/
"Need change RFgain\n"));
}
"calibration of channel %u failed\n",
}
}
static void
ath_watchdog(void *arg)
{
int ntimer = 0;
ic->ic_watchdog_timer = 0;
if (!ATH_IS_RUNNING(asc)) {
return;
}
/* periodic recalibration */
/*
* Start the background rate control thread if we
* are not configured to use a fixed xmit rate.
*/
else
ath_rate_cb, asc);
}
ntimer = 1;
}
if (ntimer != 0)
}
static uint_t
{
if (!ATH_IS_RUNNING(asc)) {
/*
* Note this can happen early on if the IRQ is shared.
*/
return (DDI_INTR_UNCLAIMED);
}
return (DDI_INTR_UNCLAIMED);
}
if (status & HAL_INT_FATAL) {
goto reset;
} else if (status & HAL_INT_RXORN) {
goto reset;
} else {
if (status & HAL_INT_RXEOL) {
}
if (status & HAL_INT_TXURN) {
}
if (status & HAL_INT_RX) {
}
if (status & HAL_INT_TX) {
}
if (status & HAL_INT_SWBA) {
/* This will occur only in Host-AP or Ad-Hoc mode */
return (DDI_INTR_CLAIMED);
}
if (status & HAL_INT_BMISS) {
(void) ieee80211_new_state(ic,
IEEE80211_S_ASSOC, -1);
}
}
}
return (DDI_INTR_CLAIMED);
return (DDI_INTR_CLAIMED);
}
static uint_t
{
/*
* Check if the soft interrupt is triggered by another
* driver at the same level.
*/
asc->asc_rx_pend = 0;
return (DDI_INTR_CLAIMED);
}
return (DDI_INTR_UNCLAIMED);
}
/*
* following are gld callback routine
* ath_gld_send, ath_gld_ioctl, ath_gld_gstat
* are listed in other corresponding sections.
* reset the hardware w/o losing operational state. this is
* basically a more efficient way of doing ath_gld_stop, ath_gld_start,
* followed by state transitions to the current 802.11
* operational state. used to recover from errors rx overrun
* and to reset the hardware when rf gain settings must be reset.
*/
static void
{
/*
* Shutdown the hardware and driver:
* reset 802.11 state machine
* turn off timers
* disable interrupts
* turn off the radio
* clear transmit machinery
* clear receive machinery
* drain and release tx queues
* reclaim beacon resources
* power down hardware
*
* Note that some of this work is not possible if the
* hardware is gone (invalid).
*/
ATH_HAL_INTRSET(ah, 0);
if (ATH_IS_RUNNING(asc)) {
} else {
}
}
static void
ath_m_stop(void *arg)
{
}
int
ath_m_start(void *arg)
{
/*
* Stop anything previously setup. This is safe
* whether this is the first time through or not.
*/
/*
* The basic interface to setting the hardware in a good
* state is ``reset''. On return the hardware is known to
* be powered up and with interrupts disabled. This must
* be followed by initialization of the appropriate bits
* and then setup of the interrupt mask.
*/
"reset hardware failed, hal status %u\n", status));
return (ENOTACTIVE);
}
(void) ath_startrecv(asc);
/*
* Enable interrupts.
*/
/*
* The hardware should be ready to go now so it's safe
* to kick the 802.11 state machine as it's likely to
* immediately call back to us to send mgmt frames.
*/
asc->asc_invalid = 0;
return (0);
}
static int
{
"%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
return (0);
}
static int
{
if (on)
else
rfilt &= ~HAL_RX_FILTER_PROM;
return (0);
}
static int
{
/* disable multicast */
if (!add) {
return (0);
}
/* enable multicast */
/* calculate XOR of eight 6bit values */
pos &= 0x3f;
return (0);
}
static void
{
if (ATH_IS_RUNNING(asc)) {
(void) ath_m_start(asc);
IEEE80211_S_SCAN, -1);
}
}
}
static int
{
switch (stat) {
case MAC_STAT_IFSPEED:
1000000ull;
break;
case MAC_STAT_NOXMTBUF:
break;
case MAC_STAT_IERRORS:
break;
case MAC_STAT_RBYTES:
break;
case MAC_STAT_IPACKETS:
break;
case MAC_STAT_OBYTES:
break;
case MAC_STAT_OPACKETS:
break;
case MAC_STAT_OERRORS:
case WIFI_STAT_TX_FAILED:
break;
case WIFI_STAT_TX_RETRANS:
break;
case WIFI_STAT_FCS_ERRORS:
break;
case WIFI_STAT_WEP_ERRORS:
break;
case WIFI_STAT_TX_FRAGS:
case WIFI_STAT_MCAST_TX:
case WIFI_STAT_RTS_SUCCESS:
case WIFI_STAT_RTS_FAILURE:
case WIFI_STAT_ACK_FAILURE:
case WIFI_STAT_RX_FRAGS:
case WIFI_STAT_MCAST_RX:
case WIFI_STAT_RX_DUPS:
default:
return (ENOTSUP);
}
return (0);
}
static int
{
const char *athname;
char strbuf[32];
int instance;
wifi_data_t wd = { 0 };
if (cmd != DDI_ATTACH)
return (DDI_FAILURE);
"Unable to alloc softstate\n"));
return (DDI_FAILURE);
}
if (err != DDI_SUCCESS) {
"pci_config_setup() failed"));
goto attach_fail0;
}
/*
* Enable response to memory space accesses,
* and enabe bus master.
*/
"set command reg to 0x%x \n", command));
if ((val & 0x0000ff00) != 0)
if (err != DDI_SUCCESS) {
"ddi_regs_map_setup() failed"));
goto attach_fail1;
}
"unable to attach hw; HAL status %u\n", status));
goto attach_fail2;
}
ATH_HAL_INTRSET(ah, 0);
"HAL ABI mismatch detected (0x%x != 0x%x)\n",
goto attach_fail3;
}
"HAL mac version %d.%d, phy version %d.%d\n",
if (ah->ah_analog5GhzRev)
"HAL 5ghz radio version %d.%d\n",
if (ah->ah_analog2GhzRev)
"HAL 2ghz radio version %d.%d\n",
/*
* Check if the MAC has multi-rate retry support.
* We do this by trying to setup a fake extended
* descriptor. MAC's that don't have support will
* return false w/o doing anything. MAC's that do
* support it will return true w/o doing anything.
*/
"multi rate retry support=%x\n",
asc->asc_mrretry));
/*
* Collect the channel list using the default country
* code and including outdoor channels. The 802.11 layer
* is resposible for filtering this list to a set of
* channels that it considers ok to use.
*/
asc->asc_have11g = 0;
/* enable outdoor use, enable extended channels */
if (err != 0)
goto attach_fail3;
/*
* Setup rate tables for all potential media types.
*/
/* Setup here so ath_rate_update is happy */
if (err != DDI_SUCCESS) {
"failed to allocate descriptors: %d\n", err));
goto attach_fail3;
}
/* Setup transmit queues in the HAL */
if (ath_txq_setup(asc))
goto attach_fail4;
/*
* Initialize pointers to device specific functions which
* will be used by the generic layer.
*/
/* 11g support is identified when we fetch the channel set */
if (asc->asc_have11g)
/*
* Query the hal to figure out h/w crypto support.
*/
/*
* separate key cache entries are required to
* handle both tx+rx MIC keys.
*/
if (ATH_HAL_TKIPSPLIT(ah))
}
/* Override 80211 default routines */
asc->asc_rx_pend = 0;
ATH_HAL_INTRSET(ah, 0);
if (err != DDI_SUCCESS) {
"ddi_add_softintr() failed\n"));
goto attach_fail5;
}
!= DDI_SUCCESS) {
"Can not get iblock cookie for INT\n"));
goto attach_fail6;
}
"Can not set intr for ATH driver\n"));
goto attach_fail6;
}
/*
* Provide initial settings for the WiFi plugin; whenever this
* information changes, we need to call mac_plugindata_update()
*/
"MAC version mismatch\n"));
goto attach_fail7;
}
if (err != 0) {
"mac_register err %x\n", err));
goto attach_fail7;
}
/* Create minor node of type DDI_NT_NET_WIFI */
if (err != DDI_SUCCESS)
"Create minor node failed - %d\n", err));
return (DDI_SUCCESS);
(void) ieee80211_detach(ic);
for (i = 0; i < HAL_NUM_TX_QUEUES; i++) {
if (ATH_TXQ_SETUP(asc, i)) {
}
}
return (DDI_FAILURE);
}
static int32_t
{
if (cmd != DDI_DETACH)
return (DDI_FAILURE);
/* disable interrupts */
/*
* Unregister from the MAC layer subsystem
*/
return (DDI_FAILURE);
/* free intterrupt resources */
/*
* NB: the order of these is important:
* o call the 802.11 layer before detaching the hal to
* insure callbacks into the driver to delete global
* key cache entries can be handled
* o reclaim the tx queue data structures after calling
* the 802.11 layer as we'll get called back to reclaim
* node state and potentially want to use them
* o to cleanup the tx queues the hal is called, so detach
* it last
*/
/* free io handle */
/* destroy locks */
return (DDI_SUCCESS);
}
static struct modldrv ath_modldrv = {
&mod_driverops, /* Type of module. This one is a driver */
"ath driver 1.2/HAL 0.9.17.2", /* short description */
&ath_dev_ops /* driver specific ops */
};
static struct modlinkage modlinkage = {
};
int
{
}
int
_init(void)
{
int status;
if (status != 0)
return (status);
if (status != 0) {
}
return (status);
}
int
_fini(void)
{
int status;
if (status == 0) {
}
return (status);
}