/*-
* Copyright (c) 1998, 1999, 2000, 2002, 2003, 2004 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by David Young, by Jason R. Thorpe, and by Charles M. Hannum.
*
* 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.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 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 DAMAGE.
*/
/*
* Device driver for the ADMtek ADM8211 802.11 MAC/BBP.
*/
/* XXX TBD open questions
*
*
* When should I set DSSS PAD in reg 0x15 of RF3000? In 1-2Mbps
* modes only, or all modes (5.5-11 Mbps CCK modes, too?) Does the MAC
* handle this for me?
*
*/
/* device attachment
*
* print TOFS[012]
*
* device initialization
*
* clear ATW_FRCTL_MAXPSP to disable max power saving
* set ATW_TXBR_ALCUPDATE to enable ALC
* set TOFS[012]? (hope not)
* disable rx/tx
* set ATW_PAR_SWR (software reset)
* wait for ATW_PAR_SWR clear
* disable interrupts
* ack status register
* enable interrupts
*
* rx/tx initialization
*
* disable rx/tx w/ ATW_NAR_SR, ATW_NAR_ST
* allocate and init descriptor rings
* write ATW_PAR_DSL (descriptor skip length)
* write descriptor base addrs: ATW_TDBD, ATW_TDBP, write ATW_RDB
* write ATW_NAR_SQ for one/both transmit descriptor rings
* write ATW_NAR_SQ for one/both transmit descriptor rings
* enable rx/tx w/ ATW_NAR_SR, ATW_NAR_ST
*
* rx/tx end
*
* stop DMA
* disable rx/tx w/ ATW_NAR_SR, ATW_NAR_ST
* flush tx w/ ATW_NAR_HF
*
* scan
*
* initialize rx/tx
*
* BSS join: (re)association response
*
* set ATW_FRCTL_AID
*
* optimizations ???
*
*/
#define ATW_REFSLAVE /* slavishly do what the reference driver does */
int atw_pseudo_milli = 1;
int atw_magic_delay1 = 100 * 1000;
int atw_magic_delay2 = 100 * 1000;
/* more magic multi-millisecond delays (units: microseconds) */
int atw_nar_delay = 20 * 1000;
int atw_magic_delay4 = 10 * 1000;
int atw_rf_delay1 = 10 * 1000;
int atw_rf_delay2 = 5 * 1000;
int atw_plcphd_delay = 2 * 1000;
int atw_bbp_io_enable_delay = 20 * 1000;
int atw_bbp_io_disable_delay = 2 * 1000;
int atw_writewep_delay = 1000;
int atw_beacon_len_adjust = 4;
int atw_dwelltime = 200;
int atw_xindiv2 = 0;
#ifdef ATW_DEBUG
int atw_debug = 0;
#define ATW_DPRINTF(x) if (atw_debug > 0) printf x
#define ATW_DPRINTF2(x) if (atw_debug > 1) printf x
#define ATW_DPRINTF3(x) if (atw_debug > 2) printf x
#define DPRINTF(sc, x) if ((sc)->sc_if.if_flags & IFF_DEBUG) printf x
#define DPRINTF2(sc, x) if ((sc)->sc_if.if_flags & IFF_DEBUG) ATW_DPRINTF2(x)
#define DPRINTF3(sc, x) if ((sc)->sc_if.if_flags & IFF_DEBUG) ATW_DPRINTF3(x)
/* ADM8211 has a single 32-bit register for controlling the
* 93cx6 SROM. Bit SRS enables the serial port. There is no
* "ready" bit. The ADM8211 input/output sense is the reverse
* of read_seeprom's.
*/
sd.sd_tag = sc->sc_st;
sd.sd_bsh = sc->sc_sh;
sd.sd_regsize = 4;
sd.sd_control_offset = ATW_SPR;
sd.sd_status_offset = ATW_SPR;
sd.sd_dataout_offset = ATW_SPR;
sd.sd_CK = ATW_SPR_SCLK;
sd.sd_CS = ATW_SPR_SCS;
sd.sd_DI = ATW_SPR_SDO;
sd.sd_DO = ATW_SPR_SDI;
sd.sd_MS = ATW_SPR_SRS;
sd.sd_RDY = 0;
if (!read_seeprom(&sd, sc->sc_srom, 0, sc->sc_sromsz/2)) {
aprint_error_dev(sc->sc_dev, "could not read SROM\n");
free(sc->sc_srom, M_DEVBUF);
return -1;
}
#ifdef ATW_DEBUG
{
int i;
ATW_DPRINTF(("\nSerial EEPROM:\n\t"));
for (i = 0; i < sc->sc_sromsz/2; i = i + 1) {
if (((i % 8) == 0) && (i != 0)) {
ATW_DPRINTF(("\n\t"));
}
ATW_DPRINTF((" 0x%x", sc->sc_srom[i]));
}
ATW_DPRINTF(("\n"));
}
#endif /* ATW_DEBUG */
return 0;
}
/*
* Allocate the control data structures, and create and load the
* DMA map for it.
*/
if ((error = bus_dmamem_alloc(sc->sc_dmat,
sizeof(struct atw_control_data), PAGE_SIZE, 0, &sc->sc_cdseg,
1, &sc->sc_cdnseg, 0)) != 0) {
aprint_error_dev(sc->sc_dev,
"unable to allocate control data, error = %d\n",
error);
goto fail_0;
}
if ((error = bus_dmamem_map(sc->sc_dmat, &sc->sc_cdseg, sc->sc_cdnseg,
sizeof(struct atw_control_data), (void **)&sc->sc_control_data,
BUS_DMA_COHERENT)) != 0) {
aprint_error_dev(sc->sc_dev,
"unable to map control data, error = %d\n",
error);
goto fail_1;
}
if ((error = bus_dmamap_create(sc->sc_dmat,
sizeof(struct atw_control_data), 1,
sizeof(struct atw_control_data), 0, 0, &sc->sc_cddmamap)) != 0) {
aprint_error_dev(sc->sc_dev,
"unable to create control data DMA map, error = %d\n",
error);
goto fail_2;
}
if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_cddmamap,
sc->sc_control_data, sizeof(struct atw_control_data), NULL,
0)) != 0) {
aprint_error_dev(sc->sc_dev,
"unable to load control data DMA map, error = %d\n", error);
goto fail_3;
}
/*
* Create the transmit buffer DMA maps.
*/
sc->sc_ntxsegs = ATW_NTXSEGS;
for (i = 0; i < ATW_TXQUEUELEN; i++) {
if ((error = bus_dmamap_create(sc->sc_dmat, MCLBYTES,
sc->sc_ntxsegs, MCLBYTES, 0, 0,
&sc->sc_txsoft[i].txs_dmamap)) != 0) {
aprint_error_dev(sc->sc_dev,
"unable to create tx DMA map %d, error = %d\n", i,
error);
goto fail_4;
}
}
/*
* Create the receive buffer DMA maps.
*/
for (i = 0; i < ATW_NRXDESC; i++) {
if ((error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1,
MCLBYTES, 0, 0, &sc->sc_rxsoft[i].rxs_dmamap)) != 0) {
aprint_error_dev(sc->sc_dev,
"unable to create rx DMA map %d, error = %d\n", i,
error);
goto fail_5;
}
}
for (i = 0; i < ATW_NRXDESC; i++) {
sc->sc_rxsoft[i].rxs_mbuf = NULL;
}
switch (sc->sc_rev) {
case ATW_REVISION_AB:
case ATW_REVISION_AF:
sc->sc_sramlen = ATW_SRAM_A_SIZE;
break;
case ATW_REVISION_BA:
case ATW_REVISION_CA:
sc->sc_sramlen = ATW_SRAM_B_SIZE;
break;
}
/* Reset the chip to a known state. */
atw_reset(sc);
/*
* From this point forward, the attachment cannot fail. A failure
* before this point releases all resources that may have been
* allocated.
*/
sc->sc_flags |= ATWF_ATTACHED;
ATW_DPRINTF((" SROM MAC %04x%04x%04x",
htole16(sc->sc_srom[ATW_SR_MAC00]),
htole16(sc->sc_srom[ATW_SR_MAC01]),
htole16(sc->sc_srom[ATW_SR_MAC10])));
#define ADD_CHANNEL(_ic, _chan) do { \
_ic->ic_channels[_chan].ic_flags = IEEE80211_CHAN_B; \
_ic->ic_channels[_chan].ic_freq = \
ieee80211_ieee2mhz(_chan, _ic->ic_channels[_chan].ic_flags);\
} while (0)
/* Find available channels */
switch (country_code) {
case COUNTRY_MMK2: /* 1-14 */
ADD_CHANNEL(ic, 14);
/*FALLTHROUGH*/
case COUNTRY_ETSI: /* 1-13 */
for (i = 1; i <= 13; i++)
ADD_CHANNEL(ic, i);
break;
case COUNTRY_FCC: /* 1-11 */
case COUNTRY_IC: /* 1-11 */
for (i = 1; i <= 11; i++)
ADD_CHANNEL(ic, i);
break;
case COUNTRY_MMK: /* 14 */
ADD_CHANNEL(ic, 14);
break;
case COUNTRY_FRANCE: /* 10-13 */
for (i = 10; i <= 13; i++)
ADD_CHANNEL(ic, i);
break;
default: /* assume channels 10-11 */
case COUNTRY_SPAIN: /* 10-11 */
for (i = 10; i <= 11; i++)
ADD_CHANNEL(ic, i);
break;
}
/*
* Free any resources we've allocated during the failed attach
* attempt. Do this in reverse order and fall through.
*/
fail_5:
for (i = 0; i < ATW_NRXDESC; i++) {
if (sc->sc_rxsoft[i].rxs_dmamap == NULL)
continue;
bus_dmamap_destroy(sc->sc_dmat, sc->sc_rxsoft[i].rxs_dmamap);
}
fail_4:
for (i = 0; i < ATW_TXQUEUELEN; i++) {
if (sc->sc_txsoft[i].txs_dmamap == NULL)
continue;
bus_dmamap_destroy(sc->sc_dmat, sc->sc_txsoft[i].txs_dmamap);
}
bus_dmamap_unload(sc->sc_dmat, sc->sc_cddmamap);
fail_3:
bus_dmamap_destroy(sc->sc_dmat, sc->sc_cddmamap);
fail_2:
bus_dmamem_unmap(sc->sc_dmat, (void *)sc->sc_control_data,
sizeof(struct atw_control_data));
fail_1:
bus_dmamem_free(sc->sc_dmat, &sc->sc_cdseg, sc->sc_cdnseg);
fail_0:
if (sc->sc_soft_ih != NULL) {
softint_disestablish(sc->sc_soft_ih);
sc->sc_soft_ih = NULL;
}
}
/* Reference driver has a cryptic remark indicating that this might
* power-on the chip. I know that it turns off power-saving....
*/
ATW_WRITE(sc, ATW_FRCTL, 0x0);
ATW_WRITE(sc, ATW_PAR, ATW_PAR_SWR);
for (i = 0; i < 50000 / atw_pseudo_milli; i++) {
if ((ATW_READ(sc, ATW_PAR) & ATW_PAR_SWR) == 0)
break;
DELAY(atw_pseudo_milli);
}
/* ... and then pause 100ms longer for good measure. */
DELAY(atw_magic_delay1);
/* TBD atw_init
*
* set MAC based on ic->ic_bss->myaddr
* write WEP keys
* set TX rate
*/
/* Tell the ADM8211 to raise ATW_INTR_LINKOFF if 7 beacon intervals pass
* without receiving a beacon with the preferred BSSID & SSID.
* atw_write_bssid & atw_write_ssid set the BSSID & SSID.
*/
static void
atw_wcsr_init(struct atw_softc *sc)
{
uint32_t wcsr;
wcsr = ATW_READ(sc, ATW_WCSR);
wcsr &= ~ATW_WCSR_BLN_MASK;
wcsr |= __SHIFTIN(7, ATW_WCSR_BLN_MASK);
/* We always want to wake up on link loss or TSFT out of range */
wcsr |= ATW_WCSR_LSOE | ATW_WCSR_TSFTWE;
ATW_WRITE(sc, ATW_WCSR, wcsr);
static void
atw_tofs0_init(struct atw_softc *sc)
{
/* XXX I guess that the Cardbus clock is 22 MHz?
* I am assuming that the role of ATW_TOFS0_USCNT is
* to divide the bus clock to get a 1 MHz clock---the datasheet is not
* very clear on this point. It says in the datasheet that it is
* possible for the ADM8211 to accommodate bus speeds between 22 MHz
* and 33 MHz; maybe this is the way? I see a binary-only driver write
* these values. These values are also the power-on default.
*/
ATW_WRITE(sc, ATW_TOFS0,
__SHIFTIN(22, ATW_TOFS0_USCNT_MASK) |
ATW_TOFS0_TUCNT_MASK /* set all bits in TUCNT */);
}
/* Initialize interframe spacing: 802.11b slot time, SIFS, DIFS, EIFS. */
static void
atw_ifs_init(struct atw_softc *sc)
{
uint32_t ifst;
/* XXX EIFS=0x64, SIFS=110 are used by the reference driver.
* Go figure.
*/
ifst = __SHIFTIN(IEEE80211_DUR_DS_SLOT, ATW_IFST_SLOT_MASK) |
__SHIFTIN(22 * 10 /* IEEE80211_DUR_DS_SIFS */ /* # of 22 MHz cycles */,
ATW_IFST_SIFS_MASK) |
__SHIFTIN(IEEE80211_DUR_DS_DIFS, ATW_IFST_DIFS_MASK) |
__SHIFTIN(IEEE80211_DUR_DS_EIFS, ATW_IFST_EIFS_MASK);
ATW_WRITE(sc, ATW_IFST, ifst);
}
static void
atw_response_times_init(struct atw_softc *sc)
{
/* XXX More magic. Relates to ACK timing? The datasheet seems to
* indicate that the MAC expects at least SIFS + MIRT microseconds
* to pass after it transmits a frame that requires a response;
* it waits at most SIFS + MART microseconds for the response.
* Surely this is not the ACK timeout?
*/
ATW_WRITE(sc, ATW_RSPT, __SHIFTIN(0xffff, ATW_RSPT_MART_MASK) |
__SHIFTIN(0xff, ATW_RSPT_MIRT_MASK));
}
/* Set up the MMI read/write addresses for the baseband. The Tx/Rx
* engines read and write baseband registers after Rx and before
* Tx, respectively.
*/
static void
atw_bbp_io_init(struct atw_softc *sc)
{
uint32_t mmiraddr2;
/* XXX The reference driver does this, but is it *really*
* necessary?
*/
switch (sc->sc_rev) {
case ATW_REVISION_AB:
case ATW_REVISION_AF:
mmiraddr2 = 0x0;
break;
default:
mmiraddr2 = ATW_READ(sc, ATW_MMIRADDR2);
mmiraddr2 &=
~(ATW_MMIRADDR2_PROREXT | ATW_MMIRADDR2_PRORLEN_MASK);
break;
}
switch (sc->sc_bbptype) {
case ATW_BBPTYPE_INTERSIL:
ATW_WRITE(sc, ATW_MMIWADDR, ATW_MMIWADDR_INTERSIL);
ATW_WRITE(sc, ATW_MMIRADDR1, ATW_MMIRADDR1_INTERSIL);
mmiraddr2 |= ATW_MMIRADDR2_INTERSIL;
break;
case ATW_BBPTYPE_MARVEL:
/* TBD find out the Marvel settings. */
break;
case ATW_BBPTYPE_RFMD:
default:
ATW_WRITE(sc, ATW_MMIWADDR, ATW_MMIWADDR_RFMD);
ATW_WRITE(sc, ATW_MMIRADDR1, ATW_MMIRADDR1_RFMD);
mmiraddr2 |= ATW_MMIRADDR2_RFMD;
break;
}
ATW_WRITE(sc, ATW_MMIRADDR2, mmiraddr2);
ATW_WRITE(sc, ATW_MACTEST, ATW_MACTEST_MMI_USETXCLK);
}
/*
* atw_init: [ ifnet interface function ]
*
* Initialize the interface. Must be called at splnet().
*/
int
atw_init(struct ifnet *ifp)
{
struct atw_softc *sc = ifp->if_softc;
struct ieee80211com *ic = &sc->sc_ic;
struct atw_txsoft *txs;
struct atw_rxsoft *rxs;
int i, error = 0;
if (device_is_active(sc->sc_dev)) {
/*
* Cancel any pending I/O.
*/
atw_stop(ifp, 0);
} else if (!pmf_device_subtree_resume(sc->sc_dev, &sc->sc_qual) ||
!device_is_active(sc->sc_dev))
return 0;
/*
* Reset the chip to a known state.
*/
atw_reset(sc);
/* Set data rate for PLCP Signal field, 1Mbps = 10 x 100Kb/s.
*
* XXX Set transmit power for ATIM, RTS, Beacon.
*/
ATW_WRITE(sc, ATW_PLCPHD, __SHIFTIN(10, ATW_PLCPHD_SIGNAL_MASK) |
__SHIFTIN(0xb0, ATW_PLCPHD_SERVICE_MASK));
atw_tofs2_init(sc);
atw_nar_init(sc);
atw_txlmt_init(sc);
atw_test1_init(sc);
atw_rf_reset(sc);
atw_cfp_init(sc);
atw_tofs0_init(sc);
atw_ifs_init(sc);
/* XXX Fall asleep after one second of inactivity.
* XXX A frame may only dribble in for 65536us.
*/
ATW_WRITE(sc, ATW_RMD,
__SHIFTIN(1, ATW_RMD_PCNT) | __SHIFTIN(0xffff, ATW_RMD_RMRD_MASK));
/*
* Give the transmit and receive rings to the ADM8211.
*/
ATW_WRITE(sc, ATW_RDB, ATW_CDRXADDR(sc, sc->sc_rxptr));
ATW_WRITE(sc, ATW_TDBD, ATW_CDTXADDR(sc, sc->sc_txnext));
/* Tune to channel chan by adjusting the Si4126 RF/IF synthesizer.
*
* The RF/IF synthesizer produces two reference frequencies for
* the RF2948B transceiver. The first frequency the RF2948B requires
* is two times the so-called "intermediate frequency" (IF). Since
* a SAW filter on the radio fixes the IF at 374 MHz, I program the
* Si4126 to generate IF LO = 374 MHz x 2 = 748 MHz. The second
* frequency required by the transceiver is the radio frequency
* (RF). This is a superheterodyne transceiver; for f(chan) the
* center frequency of the channel we are tuning, RF = f(chan) -
* IF.
*
* XXX I am told by SiLabs that the Si4126 will accept a broader range
* of XIN than the 2-25 MHz mentioned by the datasheet, even *without*
* XINDIV2 = 1. I've tried this (it is necessary to double R) and it
* works, but I have still programmed for XINDIV2 = 1 to be safe.
*/
static void
atw_si4126_tune(struct atw_softc *sc, u_int chan)
{
u_int mhz;
u_int R;
uint32_t gpio;
uint16_t gain;
/* Tune IF to 748 MHz to suit the IF LO input of the
* RF2494B, which is 2 x IF. No need to set an IF divider
* because an IF in 526 MHz - 952 MHz is allowed.
*
* XIN is 44.000 MHz, so divide it by two to get allowable
* range of 2-25 MHz. SiLabs tells me that this is not
* strictly necessary.
*/
/* Set the phase-locked loop gain. If RF2 N > 2047, then
* set KP2 to 1.
*
* REFDIF This is different from the reference driver, which
* always sets SI4126_GAIN to 0.
*/
gain = __SHIFTIN(((mhz - 374) > 2047) ? 1 : 0, SI4126_GAIN_KP2_MASK);
atw_si4126_write(sc, SI4126_GAIN, gain);
/* XIN = 44 MHz.
*
* If XINDIV2 = 1, IF = N/(2 * R) * XIN. I choose N = 1496,
* R = 44 so that 1496/(2 * 44) * 44 MHz = 748 MHz.
*
* If XINDIV2 = 0, IF = N/R * XIN. I choose N = 1496, R = 88
* so that 1496/88 * 44 MHz = 748 MHz.
*/
atw_si4126_write(sc, SI4126_IFN, 1496);
atw_si4126_write(sc, SI4126_IFR, R);
#ifndef ATW_REFSLAVE
/* Set RF1 arbitrarily. DO NOT configure RF1 after RF2, because
* then RF1 becomes the active RF synthesizer, even on the Si4126,
* which has no RF1!
*/
atw_si4126_write(sc, SI4126_RF1R, R);
/* N/R * XIN = RF. XIN = 44 MHz. We desire RF = mhz - IF,
* where IF = 374 MHz. Let's divide XIN to 1 MHz. So R = 44.
* Now let's multiply it to mhz. So mhz - IF = N.
*/
atw_si4126_write(sc, SI4126_RF2R, R);
atw_si4126_write(sc, SI4126_RF2N, mhz - 374);
/* wait 100us from power-up for RF, IF to settle */
DELAY(100);
if ((sc->sc_if.if_flags & IFF_LINK1) != 0 && chan != 14) {
/* Set a Prism RF front-end to a special mode for channel 14?
*
* Apparently the SMC2635W needs this, although I don't think
* it has a Prism RF.
*/
gpio |= __SHIFTIN(1, ATW_GPIO_O_MASK);
}
ATW_WRITE(sc, ATW_GPIO, gpio);
/* XXX Reference driver remarks that Abocom sets this to 50.
* Meaning 0x50, I think.... 50 = 0x32, which would set a bit
* in the "reserved" area of register RF3000_OPTIONS1.
*/
rc = atw_rf3000_write(sc, RF3000_OPTIONS1, sc->sc_rf3000_options1);
/* Set the power settings on the BBP for channel `chan'. */
static int
atw_rf3000_tune(struct atw_softc *sc, u_int chan)
{
int rc = 0;
uint32_t reg;
uint16_t txpower, lpf_cutoff, lna_gs_thresh;
/* Write a register on the RF3000 baseband processor using the
* registers provided by the ADM8211 for this purpose.
*
* Return 0 on success.
*/
static int
atw_rf3000_write(struct atw_softc *sc, u_int addr, u_int val)
{
uint32_t reg;
int i;
for (i = 20000 / atw_pseudo_milli; --i >= 0; ) {
ATW_WRITE(sc, ATW_BBPCTL, reg);
DELAY(2 * atw_pseudo_milli);
if (ATW_ISSET(sc, ATW_BBPCTL, ATW_BBPCTL_WR) == 0)
break;
}
if (i < 0) {
printf("%s: BBPCTL still busy\n", device_xname(sc->sc_dev));
return ETIMEDOUT;
}
return 0;
}
/* Read a register on the RF3000 baseband processor using the registers
* the ADM8211 provides for this purpose.
*
* The 7-bit register address is addr. Record the 8-bit data in the register
* in *val.
*
* Return 0 on success.
*
* XXX This does not seem to work. The ADM8211 must require more or
* different magic to read the chip than to write it. Possibly some
* of the magic I have derived from a binary-only driver concerns
* the "chip address" (see the RF3000 manual).
*/
#ifdef ATW_BBPDEBUG
static int
atw_rf3000_read(struct atw_softc *sc, u_int addr, u_int *val)
{
uint32_t reg;
int i;
for (i = 1000; --i >= 0; ) {
if (ATW_ISSET(sc, ATW_BBPCTL, ATW_BBPCTL_RD | ATW_BBPCTL_WR)
== 0)
break;
DELAY(100);
}
if (i < 0) {
printf("%s: start atw_rf3000_read, BBPCTL busy\n",
device_xname(sc->sc_dev));
return ETIMEDOUT;
}
for (i = 1000; --i >= 0; ) {
DELAY(100);
if (ATW_ISSET(sc, ATW_BBPCTL, ATW_BBPCTL_RD) == 0)
break;
}
ATW_CLR(sc, ATW_BBPCTL, ATW_BBPCTL_RD);
if (i < 0) {
printf("%s: atw_rf3000_read wrote %08x; BBPCTL still busy\n",
device_xname(sc->sc_dev), reg);
return ETIMEDOUT;
}
if (val != NULL)
*val = __SHIFTOUT(reg, ATW_BBPCTL_DATA_MASK);
return 0;
}
#endif /* ATW_BBPDEBUG */
/* Write a register on the Si4126 RF/IF synthesizer using the registers
* provided by the ADM8211 for that purpose.
*
* val is 18 bits of data, and val is the 4-bit address of the register.
*
* Return 0 on success.
*/
static void
atw_si4126_write(struct atw_softc *sc, u_int addr, u_int val)
{
uint32_t bits, mask, reg;
const int nbits = 22;
/* Read 18-bit data from the 4-bit address addr in Si4126
* RF synthesizer and write the data to *val. Return 0 on success.
*
* XXX This does not seem to work. The ADM8211 must require more or
* different magic to read the chip than to write it.
*/
#ifdef ATW_SYNDEBUG
static int
atw_si4126_read(struct atw_softc *sc, u_int addr, u_int *val)
{
uint32_t reg;
int i;
/* According to comments in tlp_al981_filter_setup
* (dev/ic/tulip.c) the ADMtek AL981 does not like for its
* multicast filter to be set while it is running. Hopefully
* the ADM8211 is not the same!
*/
if ((ifp->if_flags & IFF_RUNNING) != 0)
atw_idle(sc, ATW_NAR_SR);
/* Tell the ADM8211 our preferred BSSID. The ADM8211 must match
* a beacon's BSSID and SSID against the preferred BSSID and SSID
* before it will raise ATW_INTR_LINKON. When the ADM8211 receives
* no beacon with the preferred BSSID and SSID in the number of
* beacon intervals given in ATW_BPLI, then it raises ATW_INTR_LINKOFF.
*/
static void
atw_write_bssid(struct atw_softc *sc)
{
struct ieee80211com *ic = &sc->sc_ic;
uint8_t *bssid;
/* The ADM8211A answers probe requests. TBD ADM8211B/C. */
if (subtype == IEEE80211_FC0_SUBTYPE_PROBE_REQ)
return;
(*sc->sc_recv_mgmt)(ic, m, ni, subtype, rssi, rstamp);
switch (subtype) {
case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
case IEEE80211_FC0_SUBTYPE_BEACON:
if (ic->ic_opmode == IEEE80211_M_IBSS &&
ic->ic_state == IEEE80211_S_RUN) {
if (le64toh(ni->ni_tstamp.tsf) >= atw_get_tsft(sc))
(void)ieee80211_ibss_merge(ni);
}
break;
default:
break;
}
return;
}
/* Write the SSID in the ieee80211com to the SRAM on the ADM8211.
* In ad hoc mode, the SSID is written to the beacons sent by the
* ADM8211. In both ad hoc and infrastructure mode, beacons received
* with matching SSID affect ATW_INTR_LINKON/ATW_INTR_LINKOFF
* indications.
*/
static void
atw_write_ssid(struct atw_softc *sc)
{
struct ieee80211com *ic = &sc->sc_ic;
/* 34 bytes are reserved in ADM8211 SRAM for the SSID, but
* it only expects the element length, not its ID.
*/
uint8_t buf[roundup(1 /* length */ + IEEE80211_NWID_LEN, 2)];
/* Write the supported rates in the ieee80211com to the SRAM of the ADM8211.
* In ad hoc mode, the supported rates are written to beacons sent by the
* ADM8211.
*/
static void
atw_write_sup_rates(struct atw_softc *sc)
{
struct ieee80211com *ic = &sc->sc_ic;
/* 14 bytes are probably (XXX) reserved in the ADM8211 SRAM for
* supported rates
*/
uint8_t buf[roundup(1 /* length */ + IEEE80211_RATE_SIZE, 2)];
/* Return the 32 lsb of the last TSFT divisible by ival. */
static inline uint32_t
atw_last_even_tsft(uint32_t tsfth, uint32_t tsftl, uint32_t ival)
{
/* Following the reference driver's lead, I compute
*
* (uint32_t)((((uint64_t)tsfth << 32) | tsftl) % ival)
*
* without using 64-bit arithmetic, using the following
* relationship:
*
* (0x100000000 * H + L) % m
* = ((0x100000000 % m) * H + L) % m
* = (((0xffffffff + 1) % m) * H + L) % m
* = ((0xffffffff % m + 1 % m) * H + L) % m
* = ((0xffffffff % m + 1) * H + L) % m
*/
return ((0xFFFFFFFF % ival + 1) * tsfth + tsftl) % ival;
}
static uint64_t
atw_get_tsft(struct atw_softc *sc)
{
int i;
uint32_t tsfth, tsftl;
for (i = 0; i < 2; i++) {
tsfth = ATW_READ(sc, ATW_TSFTH);
tsftl = ATW_READ(sc, ATW_TSFTL);
if (ATW_READ(sc, ATW_TSFTH) == tsfth)
break;
}
return ((uint64_t)tsfth << 32) | tsftl;
}
/* If we've created an IBSS, write the TSF time in the ADM8211 to
* the ieee80211com.
*
* Predict the next target beacon transmission time (TBTT) and
* write it to the ADM8211.
*/
static void
atw_predict_beacon(struct atw_softc *sc)
{
#define TBTTOFS 20 /* TU */
/* We sent/received the last beacon `past' microseconds
* after the interval divided the TSF timer.
*/
past_even = tsftl - atw_last_even_tsft(tsfth, tsftl, ival);
/* Skip ten beacons so that the TBTT cannot pass before
* we've programmed it. Ten is an arbitrary number.
*/
tbtt = past_even + ival * 10;
/* don't call atw_start w/o network interrupts blocked */
s = splnet();
if (ic->ic_state == IEEE80211_S_SCAN)
ieee80211_next_scan(ic);
splx(s);
}
/* Synchronize the hardware state with the software state. */
static int
atw_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
{
struct ifnet *ifp = ic->ic_ifp;
struct atw_softc *sc = ifp->if_softc;
int error = 0;
callout_stop(&sc->sc_scan_ch);
switch (nstate) {
case IEEE80211_S_AUTH:
case IEEE80211_S_ASSOC:
atw_write_bssid(sc);
error = atw_tune(sc);
break;
case IEEE80211_S_INIT:
callout_stop(&sc->sc_scan_ch);
sc->sc_cur_chan = IEEE80211_CHAN_ANY;
atw_start_beacon(sc, 0);
break;
case IEEE80211_S_SCAN:
error = atw_tune(sc);
callout_reset(&sc->sc_scan_ch, atw_dwelltime * hz / 1000,
atw_next_scan, sc);
break;
case IEEE80211_S_RUN:
error = atw_tune(sc);
atw_write_bssid(sc);
atw_write_ssid(sc);
atw_write_sup_rates(sc);
if (ic->ic_opmode == IEEE80211_M_AHDEMO ||
ic->ic_opmode == IEEE80211_M_MONITOR)
break;
/* set listen interval
* XXX do software units agree w/ hardware?
*/
ATW_WRITE(sc, ATW_BPLI,
__SHIFTIN(ic->ic_bss->ni_intval, ATW_BPLI_BP_MASK) |
__SHIFTIN(ic->ic_lintval / ic->ic_bss->ni_intval,
ATW_BPLI_LI_MASK));
switch (ic->ic_opmode) {
case IEEE80211_M_AHDEMO:
case IEEE80211_M_HOSTAP:
case IEEE80211_M_IBSS:
atw_start_beacon(sc, 1);
break;
case IEEE80211_M_MONITOR:
case IEEE80211_M_STA:
break;
}
/*
* Mark the interface down and cancel the watchdog timer.
*/
ifp->if_flags &= ~IFF_RUNNING;
ifp->if_timer = 0;
if (disable)
pmf_device_suspend(sc->sc_dev, &sc->sc_qual);
}
/*
* atw_rxdrain:
*
* Drain the receive queue.
*/
void
atw_rxdrain(struct atw_softc *sc)
{
struct atw_rxsoft *rxs;
int i;
for (i = 0; i < ATW_NRXDESC; i++) {
rxs = &sc->sc_rxsoft[i];
if (rxs->rxs_mbuf == NULL)
continue;
bus_dmamap_unload(sc->sc_dmat, rxs->rxs_dmamap);
m_freem(rxs->rxs_mbuf);
rxs->rxs_mbuf = NULL;
}
}
/*
* atw_detach:
*
* Detach an ADM8211 interface.
*/
int
atw_detach(struct atw_softc *sc)
{
struct ifnet *ifp = &sc->sc_if;
struct atw_rxsoft *rxs;
struct atw_txsoft *txs;
int i;
/*
* Succeed now if there isn't any work to do.
*/
if ((sc->sc_flags & ATWF_ATTACHED) == 0)
return (0);
pmf_device_deregister(sc->sc_dev);
callout_stop(&sc->sc_scan_ch);
ieee80211_ifdetach(&sc->sc_ic);
if_detach(ifp);
for (i = 0; i < ATW_NRXDESC; i++) {
rxs = &sc->sc_rxsoft[i];
if (rxs->rxs_mbuf != NULL) {
bus_dmamap_unload(sc->sc_dmat, rxs->rxs_dmamap);
m_freem(rxs->rxs_mbuf);
rxs->rxs_mbuf = NULL;
}
bus_dmamap_destroy(sc->sc_dmat, rxs->rxs_dmamap);
}
for (i = 0; i < ATW_TXQUEUELEN; i++) {
txs = &sc->sc_txsoft[i];
if (txs->txs_mbuf != NULL) {
bus_dmamap_unload(sc->sc_dmat, txs->txs_dmamap);
m_freem(txs->txs_mbuf);
txs->txs_mbuf = NULL;
}
bus_dmamap_destroy(sc->sc_dmat, txs->txs_dmamap);
}
bus_dmamap_unload(sc->sc_dmat, sc->sc_cddmamap);
bus_dmamap_destroy(sc->sc_dmat, sc->sc_cddmamap);
bus_dmamem_unmap(sc->sc_dmat, (void *)sc->sc_control_data,
sizeof(struct atw_control_data));
bus_dmamem_free(sc->sc_dmat, &sc->sc_cdseg, sc->sc_cdnseg);
if (sc->sc_srom)
free(sc->sc_srom, M_DEVBUF);
atw_evcnt_detach(sc);
if (sc->sc_soft_ih != NULL) {
softint_disestablish(sc->sc_soft_ih);
sc->sc_soft_ih = NULL;
}
return (0);
}
/* atw_shutdown: make sure the interface is stopped at reboot time. */
bool
atw_shutdown(device_t self, int flags)
{
struct atw_softc *sc = device_private(self);
#ifdef DEBUG
if (!device_activation(sc->sc_dev, DEVACT_LEVEL_DRIVER))
panic("%s: atw_intr: not enabled", device_xname(sc->sc_dev));
#endif
/*
* If the interface isn't running, the interrupt couldn't
* possibly have come from us.
*/
if ((ifp->if_flags & IFF_RUNNING) == 0 ||
!device_activation(sc->sc_dev, DEVACT_LEVEL_DRIVER))
return (0);
status = ATW_READ(sc, ATW_STSR);
if (status == 0)
return 0;
rxstatus = status & sc->sc_rxint_mask;
txstatus = status & sc->sc_txint_mask;
linkstatus = status & sc->sc_linkint_mask;
if (linkstatus) {
atw_linkintr(sc, linkstatus);
}
if (rxstatus) {
/* Grab any new packets. */
atw_rxintr(sc);
if (rxstatus & ATW_INTR_RDU) {
printf("%s: receive ring overrun\n",
device_xname(sc->sc_dev));
/* Get the receive process going again. */
ATW_WRITE(sc, ATW_RDR, 0x1);
}
}
if (txstatus) {
/* Sweep up transmit descriptors. */
atw_txintr(sc, txstatus);
/* Set the new threshold and restart
* the transmit process.
*/
ATW_WRITE(sc, ATW_NAR, sc->sc_opmode);
DELAY(atw_nar_delay);
ATW_WRITE(sc, ATW_TDR, 0x1);
/* XXX Log every Nth underrun from
* XXX now on?
*/
}
}
if (status & (ATW_INTR_TPS | ATW_INTR_RPS)) {
if (status & ATW_INTR_TPS)
printf("%s: transmit process stopped\n",
device_xname(sc->sc_dev));
if (status & ATW_INTR_RPS)
printf("%s: receive process stopped\n",
device_xname(sc->sc_dev));
s = splnet();
(void)atw_init(ifp);
splx(s);
break;
}
if (status & ATW_INTR_FBE) {
aprint_error_dev(sc->sc_dev, "fatal bus error\n");
s = splnet();
(void)atw_init(ifp);
splx(s);
break;
}
/*
* Not handled:
*
* Transmit buffer unavailable -- normal
* condition, nothing to do, really.
*
* Early receive interrupt -- not available on
* all chips, we just use RI. We also only
* use single-segment receive DMA, so this
* is mostly useless.
*
* TBD others
*/
}
/* Try to get more packets going. */
s = splnet();
atw_start(ifp);
splx(s);
/*
* atw_idle:
*
* Cause the transmit and/or receive processes to go idle.
*
* XXX It seems that the ADM8211 will not signal the end of the Rx/Tx
* process in STSR if I clear SR or ST after the process has already
* ceased. Fair enough. But the Rx process status bits in ATW_TEST0
* do not seem to be too reliable. Perhaps I have the sense of the
* Rx bits switched with the Tx bits?
*/
void
atw_idle(struct atw_softc *sc, uint32_t bits)
{
uint32_t ackmask = 0, opmode, stsr, test0;
int i, s;
s = splnet();
opmode = sc->sc_opmode & ~bits;
if (bits & ATW_NAR_SR)
ackmask |= ATW_INTR_RPS;
if (bits & ATW_NAR_ST) {
ackmask |= ATW_INTR_TPS;
/* set ATW_NAR_HF to flush TX FIFO. */
opmode |= ATW_NAR_HF;
}
/*
* Make sure the packet fits in one buffer. This should
* always be the case.
*/
if ((rxstat & (ATW_RXSTAT_FS | ATW_RXSTAT_LS)) !=
(ATW_RXSTAT_FS | ATW_RXSTAT_LS)) {
printf("%s: incoming packet spilled, resetting\n",
device_xname(sc->sc_dev));
(void)atw_init(ifp);
return;
}
/*
* If an error occurred, update stats, clear the status
* word, and leave the packet buffer in place. It will
* simply be reused the next time the ring comes around.
*/
if ((rxstat & (ATW_RXSTAT_DE | ATW_RXSTAT_RXTOE)) != 0) {
#define PRINTERR(bit, str) \
if (rxstat & (bit)) \
aprint_error_dev(sc->sc_dev, "receive error: %s\n", \
str)
if_statinc(ifp, if_ierrors);
PRINTERR(ATW_RXSTAT_DE, "descriptor error");
PRINTERR(ATW_RXSTAT_RXTOE, "time-out");
#if 0
PRINTERR(ATW_RXSTAT_SFDE, "PLCP SFD error");
PRINTERR(ATW_RXSTAT_SIGE, "PLCP signal error");
PRINTERR(ATW_RXSTAT_CRC16E, "PLCP CRC16 error");
PRINTERR(ATW_RXSTAT_ICVE, "WEP ICV error");
#endif
#undef PRINTERR
atw_init_rxdesc(sc, i);
continue;
}
/*
* No errors; receive the packet. Note the ADM8211
* includes the CRC in promiscuous mode.
*/
len = __SHIFTOUT(rxstat, ATW_RXSTAT_FL_MASK);
/*
* Allocate a new mbuf cluster. If that fails, we are
* out of memory, and must drop the packet and recycle
* the buffer that's already attached to this descriptor.
*/
m = rxs->rxs_mbuf;
if (atw_add_rxbuf(sc, i) != 0) {
if_statinc(ifp, if_ierrors);
bus_dmamap_sync(sc->sc_dmat, rxs->rxs_dmamap, 0,
rxs->rxs_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD);
atw_init_rxdesc(sc, i);
continue;
}
/* The RSSI comes straight from a register in the
* baseband processor. I know that for the RF3000,
* the RSSI register also contains the antenna-selection
* bits. Mask those off.
*
* TBD Treat other basebands.
* TBD Use short-preamble bit and such in RF3000_RXSTAT.
*/
if (sc->sc_bbptype == ATW_BBPTYPE_RFMD)
rssi = ctlrssi & RF3000_RSSI_MASK;
else
rssi = ctlrssi;
s = splnet();
/* Pass this up to any BPF listeners. */
if (sc->sc_radiobpf != NULL) {
struct atw_rx_radiotap_header *tap = &sc->sc_rxtap;
tap->ar_rate = rate;
/* TBD verify units are dB */
tap->ar_antsignal = (int)rssi;
if (sc->sc_opmode & ATW_NAR_PR)
tap->ar_flags = IEEE80211_RADIOTAP_F_FCS;
else
tap->ar_flags = 0;
if ((rxstat & ATW_RXSTAT_CRC32E) != 0)
tap->ar_flags |= IEEE80211_RADIOTAP_F_BADFCS;
bpf_mtap2(sc->sc_radiobpf, tap, sizeof(sc->sc_rxtapu),
m, BPF_D_IN);
}
sc->sc_recv_ev.ev_count++;
if ((rxstat & (ATW_RXSTAT_CRC16E | ATW_RXSTAT_CRC32E |
ATW_RXSTAT_ICVE | ATW_RXSTAT_SFDE | ATW_RXSTAT_SIGE))
!= 0) {
if (rxstat & ATW_RXSTAT_CRC16E)
sc->sc_crc16e_ev.ev_count++;
if (rxstat & ATW_RXSTAT_CRC32E)
sc->sc_crc32e_ev.ev_count++;
if (rxstat & ATW_RXSTAT_ICVE)
sc->sc_icve_ev.ev_count++;
if (rxstat & ATW_RXSTAT_SFDE)
sc->sc_sfde_ev.ev_count++;
if (rxstat & ATW_RXSTAT_SIGE)
sc->sc_sige_ev.ev_count++;
if_statinc(ifp, if_ierrors);
m_freem(m);
splx(s);
continue;
}
if (sc->sc_opmode & ATW_NAR_PR)
m_adj(m, -IEEE80211_CRC_LEN);
/*
* Go through our Tx list and free mbufs for those
* frames that have been transmitted.
*/
while ((txs = SIMPLEQ_FIRST(&sc->sc_txdirtyq)) != NULL) {
ATW_CDTXSYNC(sc, txs->txs_lastdesc, 1,
BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
/*
* Check for errors and collisions.
*/
if (txstat & ATW_TXSTAT_TUF)
sc->sc_tuf_ev.ev_count++;
if (txstat & ATW_TXSTAT_TLT)
sc->sc_tlt_ev.ev_count++;
if (txstat & ATW_TXSTAT_TRT)
sc->sc_trt_ev.ev_count++;
if (txstat & ATW_TXSTAT_TRO)
sc->sc_tro_ev.ev_count++;
if (txstat & ATW_TXSTAT_SOFBR)
sc->sc_sofbr_ev.ev_count++;
if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
return;
/*
* Remember the previous number of free descriptors and
* the first descriptor we'll use.
*/
ofree = sc->sc_txfree;
firsttx = lasttx = sc->sc_txnext;
/*
* Loop through the send queue, setting up transmit descriptors
* until we drain the queue, or use up all available transmit
* descriptors.
*/
while ((txs = SIMPLEQ_FIRST(&sc->sc_txfreeq)) != NULL &&
sc->sc_txfree != 0) {
hdrctl = htole16(ATW_HDRCTL_UNKNOWN1);
/*
* Grab a packet off the management queue, if it
* is not empty. Otherwise, from the data queue.
*/
IF_DEQUEUE(&ic->ic_mgtq, m0);
if (m0 != NULL) {
ni = M_GETCTX(m0, struct ieee80211_node *);
M_CLEARCTX(m0);
} else if (ic->ic_state != IEEE80211_S_RUN)
break; /* send no data until associated */
else {
IFQ_DEQUEUE(&ifp->if_snd, m0);
if (m0 == NULL)
break;
bpf_mtap(ifp, m0, BPF_D_OUT);
ni = ieee80211_find_txnode(ic,
mtod(m0, struct ether_header *)->ether_dhost);
if (ni == NULL) {
if_statinc(ifp, if_oerrors);
break;
}
if ((m0 = ieee80211_encap(ic, m0, ni)) == NULL) {
ieee80211_free_node(ni);
if_statinc(ifp, if_oerrors);
break;
}
}
rate = MAX(ieee80211_get_rate(ni), 2);
whm = mtod(m0, struct ieee80211_frame_min *);
if ((whm->i_fc[1] & IEEE80211_FC1_WEP) == 0)
k = NULL;
else if ((k = ieee80211_crypto_encap(ic, ni, m0)) == NULL) {
m_freem(m0);
ieee80211_free_node(ni);
if_statinc(ifp, if_oerrors);
break;
}
#if 0
if (IEEE80211_IS_MULTICAST(wh->i_addr1) &&
m0->m_pkthdr.len > ic->ic_fragthreshold)
hdrctl |= htole16(ATW_HDRCTL_MORE_FRAG);
#endif
if (m0->m_pkthdr.len + IEEE80211_CRC_LEN >= ic->ic_rtsthreshold)
hdrctl |= htole16(ATW_HDRCTL_RTSCTS);
/* Copy everything we need from the 802.11 header:
* Frame Control; address 1, address 3, or addresses
* 3 and 4. NIC fills in BSSID, SA.
*/
if (wh->i_fc[1] & IEEE80211_FC1_DIR_TODS) {
if (wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS)
panic("%s: illegal WDS frame",
device_xname(sc->sc_dev));
memcpy(hh->atw_dst, wh->i_addr3, IEEE80211_ADDR_LEN);
} else
memcpy(hh->atw_dst, wh->i_addr1, IEEE80211_ADDR_LEN);
hh->atw_rate = rate * 5;
/* XXX this could be incorrect if M_FCS. _encap should
* probably strip FCS just in case it sticks around in
* bridged packets.
*/
hh->atw_service = 0x00; /* XXX guess */
hh->atw_paylen = htole16(m0->m_pkthdr.len -
sizeof(struct atw_frame));
/* never fragment multicast frames */
if (IEEE80211_IS_MULTICAST(hh->atw_dst))
hh->atw_fragthr = htole16(IEEE80211_FRAG_MAX);
else {
if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) &&
(ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE))
hdrctl |= htole16(ATW_HDRCTL_SHORT_PREAMBLE);
hh->atw_fragthr = htole16(ic->ic_fragthreshold);
}
/*
* Load the DMA map. Copy and try (once) again if the packet
* didn't fit in the alloted number of segments.
*/
for (first = 1;
(error = bus_dmamap_load_mbuf(sc->sc_dmat, dmamap, m0,
BUS_DMA_WRITE | BUS_DMA_NOWAIT)) != 0 && first;
first = 0) {
MGETHDR(m, M_DONTWAIT, MT_DATA);
if (m == NULL) {
aprint_error_dev(sc->sc_dev, "unable to allocate Tx mbuf\n");
break;
}
if (m0->m_pkthdr.len > MHLEN) {
MCLGET(m, M_DONTWAIT);
if ((m->m_flags & M_EXT) == 0) {
aprint_error_dev(sc->sc_dev, "unable to allocate Tx "
"cluster\n");
m_freem(m);
break;
}
}
m_copydata(m0, 0, m0->m_pkthdr.len, mtod(m, void *));
m->m_pkthdr.len = m->m_len = m0->m_pkthdr.len;
m_freem(m0);
m0 = m;
m = NULL;
}
if (error != 0) {
aprint_error_dev(sc->sc_dev, "unable to load Tx buffer, "
"error = %d\n", error);
m_freem(m0);
break;
}
/*
* Ensure we have enough descriptors free to describe
* the packet.
*/
if (dmamap->dm_nsegs > sc->sc_txfree) {
/*
* Not enough free descriptors to transmit
* this packet. Unload the DMA map and
* drop the packet. Notify the upper layer
* that there are no more slots left.
*
* XXX We could allocate an mbuf and copy, but
* XXX it is worth it?
*/
bus_dmamap_unload(sc->sc_dmat, dmamap);
m_freem(m0);
break;
}
/*
* WE ARE NOW COMMITTED TO TRANSMITTING THE PACKET.
*/
/* XXX arbitrary retry limit; 8 because I have seen it in
* use already and maybe 0 means "no tries" !
*/
ctl = htole32(__SHIFTIN(8, ATW_TXCTL_TL_MASK));
/*
* Initialize the transmit descriptors.
*/
for (nexttx = sc->sc_txnext, seg = 0;
seg < dmamap->dm_nsegs;
seg++, nexttx = ATW_NEXTTX(nexttx)) {
/*
* If this is the first descriptor we're
* enqueueing, don't set the OWN bit just
* yet. That could cause a race condition.
* We'll do it below.
*/
txd = &sc->sc_txdescs[nexttx];
txd->at_ctl = ctl |
((nexttx == firsttx) ? 0 : htole32(ATW_TXCTL_OWN));
/*
* Store a pointer to the packet so we can free it later,
* and remember what txdirty will be once the packet is
* done.
*/
txs->txs_mbuf = m0;
txs->txs_firstdesc = sc->sc_txnext;
txs->txs_lastdesc = lasttx;
txs->txs_ndescs = dmamap->dm_nsegs;
if (sc->sc_txfree != ofree) {
DPRINTF2(sc, ("%s: packets enqueued, IC on %d, OWN on %d\n",
device_xname(sc->sc_dev), lasttx, firsttx));
/*
* Cause a transmit interrupt to happen on the
* last packet we enqueued.
*/
sc->sc_txdescs[lasttx].at_flags |= htole32(ATW_TXFLAG_IC);
ATW_CDTXSYNC(sc, lasttx, 1,
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
/*
* The entire packet chain is set up. Give the
* first descriptor to the chip now.
*/
sc->sc_txdescs[firsttx].at_ctl |= htole32(ATW_TXCTL_OWN);
ATW_CDTXSYNC(sc, firsttx, 1,
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
/* Wake up the transmitter. */
ATW_WRITE(sc, ATW_TDR, 0x1);