arn_xmit.c revision dd1de3740722a4b99a74005255effebbd20a6d70
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Copyright (c) 2008 Atheros Communications Inc.
*
* 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 <sys/mac_provider.h>
#include <sys/ethernet.h>
#include <sys/byteorder.h>
#include <inet/wifi_ioctl.h>
#include <sys/mac_wifi.h>
#include "arn_core.h"
#define BITS_PER_BYTE 8
#define OFDM_PLCP_BITS 22
#define L_STF 8
#define L_LTF 8
#define L_SIG 4
#define HT_SIG 8
#define HT_STF 4
#define OFDM_SIFS_TIME 16
static void
{
/* fill in beacon config data */
}
static void
{
"tx queue [%u] %x, link %p\n",
}
/* Drain only the data queues */
/* ARGSUSED */
static void
{
for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
if (ARN_TXQ_SETUP(sc, i)) {
/*
* The TxDMA may not really be stopped.
* Double check the hal tx pending count
*/
}
}
}
if (npend) {
/* TxDMA not stopped, reset the hal */
"Unable to stop TxDMA. Reset HAL!\n"));
if (!ath9k_hw_reset(ah,
"unable to reset hardware; hal status %u\n",
status));
}
}
for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
if (ARN_TXQ_SETUP(sc, i))
}
}
/* Setup a h/w transmit queue */
struct ath_txq *
{
struct ath9k_tx_queue_info qi;
int qnum;
qi.tqi_physCompBuf = 0;
/*
* 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.
*
* The UAPSD queue is an exception, since we take a desc-
* based intr on the EOSP frames.
*/
if (qtype == ATH9K_TX_QUEUE_UAPSD)
else
if (qnum == -1) {
/*
* NB: don't print a message, this happens
* normally on parts with too few tx queues
*/
return (NULL);
}
"hal qnum %u out of range, max %u!\n",
return (NULL);
}
txq->axq_intrcnt = 0;
txq->axq_aggr_depth = 0;
txq->axq_totalqueued = 0;
/* txq->axq_linkbuf = NULL; */
}
}
/* Reclaim resources for a setup queue */
void
{
}
/*
* Setup a hardware data transmit queue for the specified
* access control. The hal may not support all requested
* queues in which case it will return a reference to a
* previously setup queue. We record the mapping from ac's
* to h/w queues for use by arn_tx_start and also track
* the set of h/w queues being used to optimize work in the
* transmit interrupt handler and related routines.
*/
int
{
"HAL AC %u out of range, max %zu!\n",
return (0);
}
return (1);
} else
return (0);
}
int
{
int qnum;
switch (qtype) {
case ATH9K_TX_QUEUE_DATA:
"HAL AC %u out of range, max %zu!\n",
return (-1);
}
break;
case ATH9K_TX_QUEUE_BEACON:
break;
case ATH9K_TX_QUEUE_CAB:
break;
default:
qnum = -1;
}
return (qnum);
}
void
{
/*
* This assumes output has been stopped.
*/
for (;;) {
break;
}
}
}
/* Drain the transmit queues and reclaim resources */
void
{
/*
* stop beacon queue. The beacon will be freed when
* we go to INIT state
*/
"beacon queue %x\n",
}
}
{
}
{
}
/* Update parameters for a transmit queue */
int
struct ath9k_tx_queue_info *qinfo)
{
int error = 0;
struct ath9k_tx_queue_info qi;
/*
* XXX: for beacon queue, we just save the parameter.
* It will be picked up by arn_beaconq_config() when
* it's necessary.
*/
return (0);
}
"Unable to update hardware queue %u!\n", qnum));
} else {
}
return (error);
}
int
{
struct ath9k_tx_queue_info qi;
struct ath_beacon_config conf;
/*
* Ensure the readytime % is within the bounds.
*/
return (0);
}
static uint32_t
{
ATH9K_CIPHER_WEP, /* IEEE80211_CIPHER_WEP */
ATH9K_CIPHER_TKIP, /* IEEE80211_CIPHER_TKIP */
ATH9K_CIPHER_AES_OCB, /* IEEE80211_CIPHER_AES_OCB */
ATH9K_CIPHER_AES_CCM, /* IEEE80211_CIPHER_AES_CCM */
ATH9K_CIPHER_CKIP, /* IEEE80211_CIPHER_CKIP */
ATH9K_CIPHER_CLR, /* IEEE80211_CIPHER_NONE */
};
return (ATH9K_KEY_TYPE_WEP);
return (ATH9K_KEY_TYPE_TKIP);
return (ATH9K_KEY_TYPE_AES);
return (ATH9K_KEY_TYPE_CLEAR);
}
/*
* 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;
/* LINTED E_FUNC_SET_NOT_USED */
enum ath9k_pkt_type atype;
struct ath_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) {
"crypto_encap failed\n"));
/*
* 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 & ATH9K_TXDESC_NOACK) == 0 &&
rix, shortPreamble);
/* LINTED E_BAD_PTR_CAST_ALIGN */
}
/*
*/
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;
}
/* setup descriptor */
/*
* Formulate first tx descriptor with tx controls.
*/
pktlen, /* packet length */
atype, /* Atheros packet type */
MAX_RATE_POWER /* MAX_RATE_POWER */,
keyix /* ATH9K_TXKEYIX_INVALID */,
keytype /* ATH9K_KEY_TYPE_CLEAR */,
flags /* flags */);
/* LINTED E_BAD_PTR_CAST_ALIGN */
"an->an_tx_rate1sp=%d tx_rate2sp=%d tx_rate3sp=%d "
"qnum=%d rix=%d sht=%d dur = %d\n",
mbslen, /* segment length */
B_TRUE, /* first segment */
B_TRUE, /* last segment */
ds); /* first descriptor */
/* set rate related fields in tx descriptor */
#ifdef MULTIRATE_RETRY
int i;
for (i = 1; i < 4; i++) {
}
#endif
/* main rate */
rix, shortPreamble);
#ifdef MULTIRATE_RETRY
}
else
{
}
#endif
/* set dur_update_en for l-sig computation except for PS-Poll frames */
} else {
}
return (0);
}
/*
* Transmit a management frame.
* Note that management frames come directly from the 802.11 layer
* and do not honor the send queue flow control.
*/
/* Upon failure caller should free mp */
int
{
struct ieee80211_frame *wh;
int error = 0;
/* should check later */
if ((type & IEEE80211_FC0_TYPE_MASK) !=
}
return (ENXIO);
}
/* Grab a TX buffer */
/* Check if a tx buffer is available */
"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;
/* LINTED E_BAD_PTR_CAST_ALIGN */
}
break;
}
if (error != 0) {
bad:
}
}
error == 0) {
}
return (error);
}
static void
{
" %08x %08x %08x %c\n",
}
/* Process completed xmit descriptors from the specified queue */
static int
{
struct ieee80211_node *in;
struct ath_tx_status *ts;
int status;
for (;;) {
break;
}
#ifdef DEBUG
#endif
if (status == EINPROGRESS) {
break;
}
/* Successful transmition */
} 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 (sc->sc_resched_needed) {
}
}
return (nacked);
}
static void
{
int i;
int nacked = 0;
/*
* Process each active queue.
*/
for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
}
}
if (nacked)
}
/* Deferred processing of transmit interrupt */
void
arn_tx_int_proc(void *arg)
{
}