that it is either NULL or a valid mbuf. Previously, it was possible
for rtw_dequeue() to exit with 0 before initializing *mp. rtw_start()
would have used whatever trash was in *mp, which would lead to
problems later on.
tx timeouts on the beacon queue. The driver's recovery process
badly disrupts the MAC's receiver. This needs a closer look, later.
Every other fix is by Charles M. Hannum. Charles writes:
"With these, the device is quite stable under load, does not experience
xmit timeouts, no longer mysteriously freezes, and does not spew
a lot of garbage. It does, however, continue to get some "tx fifo
underflow"s.
global, SYSCTL_SETUP():
a) Removed unused sysctl variables.
rtw_io_enable():
b) Change rtw_io_enable to take a softc, and make it call
rtw_txring_fixup().
c) Enable the PCI multiple read/write bit.
d) Always reset rdb_next to 0 when starting the receive engine.
rtw_intr_rx():
e) When processing receive packets, store the next pointer in rdb_next
and read it back on the next round, to fix a race condition vs.
rtw_tune() during AP discovery and association.
f) Remove the special "skip to 0th descriptor" code, because it is no
longer needed.
rtw_collect_txring():
g) In the "force" case, stop when we catch up to the hardware xmit
pointer.
rtw_intr_beacon():
h) Resetting tdb_next here looked fishy to me, in light of changes in
rtw_collect_txring(). XXX However, this is the one part I haven't
tested.
rtw_txring_fixup():
i) Add function and line arguments, so we can print out information
about the caller.
j) In addition to reading the hardware pointer, skip over any
additional packets with OWN set -- we may have queued more.
rtw_rxring_fixup():
k) Remove this, because it's completely wrong.
rtw_intr_ioerror():
l) Don't handle receive overruns here; handle them in the normal receive
path. Also changed RTW_INTR_RX and RTW_INTR_IOERROR accordingly.
m) Do not fiddle with CR; the transmit engine is still running just
fine.
n) Do not fiddle with IMR; it was unnecessary.
o) Don't touch the receive engine at all; not necessary now that we're
leaving CR alone.
p) Remove the rtw_do_chip_reset case; it was dangerous and not actually
used.
rtw_intr():
q) Don't mask off ISR bits when we pass down the ISR value; it's not
necessary, and sometimes the other bits useful in debugging output.
rtw_seg_too_short():
r) Don't spew here; the caller will do it if necessary. (Stops spewage
in an expected case.)
rtw_rxdesc_blk:
s) Minor change to make the elements have the same order as txdesc_blk.
general:
t) Added a bunch of debugging output, #ifdef RTW_DIAG, that was useful
while investigating the ring management problems. Also moved
rtw_txring_fixup() into RTW_DIAG, as I believe the transmit pointer
is always kept in sync now, and the function has potential race
conditions.
by the NIC, re-sync the descriptor so that a cacheline will not
"cover" the NIC's modifications to the descriptor when we next
examine it.
This compiles, but I have not tested it, yet.
macros, __BIT, __BITS, SHIFTIN, SHIFTOUT, and __arraycount() from
lib/libkern/libkern.h to sys/cdefs.h. Add a __-prefix to SHIFTIN
and SHIFTOUT, and add a manual page for the bit-twiddling macros,
bits(3).
Make the __BIT and __BITS macros "widthless," as best I can, by
changing their type to uintmax_t from uint32_t. XXX The manual
page lags this change by a bit.
Define __PRIxBIT and __PRIxBITS printf(3) format strings.
ic->ic_bss, but it uses the rateset in its new ieee80211_node
argument, instead. If the rate is fixed by ic->ic_fixed_rate, but
the fixed rate is not in the node's rateset, choose a reasonable
default: prefer the lowest basic rate or, if there is no basic
rate, prefer the lowest rate, period.
Change a printf complaint to a debug message.
Adapt drivers to suit new ieee80211_get_rate calling convention.
XXX I really need to replace ieee80211_get_rate with a bitrate
XXX adaptation algorithm. Soon, soon....
I had duplicated them. Improve the macros' names. Simplify their
implementation.
A brief description of each macro is below.
BIT(n): Return a bitmask with bit m set, where the least
significant bit is bit 0.
BITS(m, n): Return a bitmask with bits m through n, inclusive,
set. It does not matter whether m>n or m<=n.
The least significant bit is bit 0.
A "bitfield" is a span of consecutive bits defined by a
bitmask, where 1s select the bits in the bitfield. SHIFTIN,
SHIFTOUT, and SHIFTOUT_MASK help read and write bitfields
from device registers.
SHIFTIN(v, mask): Left-shift bits `v' into the bitfield
defined by `mask', and return them. No
side-effects.
SHIFTOUT(v, mask): Extract and return the bitfield selected
by `mask' from `v', right-shifting the
bits so that the rightmost selected bit
is at bit 0. No side-effects.
SHIFTOUT_MASK(mask): Right-shift the bits in `mask' so that
the rightmost non-zero bit is at bit
0. This is useful for finding the
greatest unsigned value that a bitfield
can hold. No side-effects. Note that
SHIFTOUT_MASK(m) = SHIFTOUT(m, m).
Examples:
/*
* Register definitions taken from the RFMD RF3000 manual.
*/
#define RF3000_GAINCTL 0x11 /* TX variable gain control */
#define RF3000_GAINCTL_TXVGC_MASK BITS(7, 2)
#define RF3000_GAINCTL_SCRAMBLER BIT(1)
/*
* Shift the transmit power into the transmit-power field of the
* gain-control register and write it to the baseband processor.
*/
atw_rf3000_write(sc, RF3000_GAINCTL,
SHIFTIN(txpower, RF3000_GAINCTL_TXVGC_MASK));
/*
* Register definitions taken from the ADMtek ADM8211 manual.
*
*/
#define ATW_RXSTAT_OWN BIT(31) /* 1: NIC may fill descriptor */
/* ... */
#define ATW_RXSTAT_DA1 BIT(17) /* DA bit 1, admin'd address */
#define ATW_RXSTAT_DA0 BIT(16) /* DA bit 0, group address */
#define ATW_RXSTAT_RXDR_MASK BITS(15,12) /* RX data rate */
#define ATW_RXSTAT_FL_MASK BITS(11,0) /* RX frame length, last
* descriptor only
*/
/* Extract the frame length from the Rx descriptor's
* status field.
*/
len = SHIFTOUT(rxstat, ATW_RXSTAT_FL_MASK);
so invalidate the WEP key registers to force us to write the keys
back to the hardware.
Revamp key handling: use the hardware WEP engine for 40-bit and
104-bit keys, only; use software WEP for all other key lengths.
Set the hardware key length to the length of the default Tx key,
or if there is no default Tx key, use the length of the longest
WEP key.
Duration and PLCP Length fields, and delete the abominable
atw_frame_setdurs() subroutine.
Make rtw(4) use the new ieee80211_compute_duration() calling
convention.
Add an ieee80211_key argument to ieee80211_compute_duration() and
lightly constify arguments. Get the crypto header length from the
key argument instead of blithely assuming a WEP header. Add some
inline documentation. Account for data padding (IEEE80211_F_DATAPAD).
1 Added new sysctl controls for debugging.
2 Improve detection & support for hardware WEP.
3 Revamp handling of transmit descriptor rings.
4 Reliably IFF_OACTIVE when transmit descriptors are available, to
stop the transmit section of the driver from freezing up.
5 Fix beacon transmission in adhoc and hostap modes. XXX There is
a wart in hostap mode, where beacons are transmitted at 1/2 the
correct rate. Load beacon descriptors when the RTW_INTR_BINT
interrupt arrives; schedule RTW_INTR_BINT 1ms ahead of the target
beacon time.
6 Recover more gracefully from tx/rx errors: avoid
transmitter/receiver/chip resets. Try to re-synchronize software
state with hardware state---e.g., load next descriptor pointer
from hardware.
7 Activate the transmit watchdog timer for beacons as well as other
packets.
8 Introduce rtw_idle() that waits for transmit DMA to finish; call
it before resetting the transmitter.
* some 8180L cards need a longer time for the srom to initialize; patch
suggested via OpenBSD.
* some cards give '0' for USA, some give '3'; for the meantime, accept both
as being USA locale cards.
* this is RTW, not ATW. :)
back out my change to ieee80211_crypto_encap that made it free its
mbuf argument on error. I had thought it was a bug. It was not.
It's the drivers that are broken. Make an(4), atw(4), ipw(4),
iwi(4), ral(4), rtw(4), ural(4), and wi(4) free the mbuf when
ieee80211_crypto_encap returns NULL. Also, return ath(4) to the
way it was---i.e., free the mbuf.
Thanks to Sam Leffler to pointing out my mistake.
receive direction, while software handles WEP in the transmit
direction. When net80211 calls rtw's rtw_key_set with a WEP key,
I point the key's wk_cipher at our "fake" cipher, rtw_cipher_wep,
which is alike to ieee80211_cipher_wep except it provides a different
crypto-decapsulation routine, rtw_wep_decap. rtw_wep_decap copies
the key passed to it by net80211, clears the key's SWCRYPT flag,
and then calls wep_decap. Now wep_decap will decapsulate, but it
will *not* re-decrypt.
XXX I need to check whether the hardware supports 40-bit WEP,
XXX 104-bit WEP, or both, and act accordingly.
the RX direction, but not in the TX direction. The
net80211 crypto framework doesn't seem to cope very well
with the assymetry (I'm probably missing something), so
I will use software WEP for now.
net80211: In ieee80211_compute_duration, figure out whether to add
the WEP header to the packet overhead by checking the
WEP bit in the Frame Control field of the 802.11 header,
instead of checking the IEEE80211_F_PRIVACY flag.
Also, if the WEP bit is present, assume that the frame
described by (wh, len) has already already been WEP
encapsulated, and adjust the payload length accordingly.
XXX that's a grotty hack that I will have to revisit,
later.
The __UNCONST macro is now used only where necessary and the RW macros
are gone. Most of the changes here are consumers of the
sysctl_createv(9) interface that now takes a pair of const pointers
which used not to be.
Fix the work-around for the NIC bug where it skips to rx
descriptor 0. The driver used to skip to rx descriptor 1.
Hopefully this stops the out-of-order packet reception that
Charles Hannum saw.
When debugging is enabled, print rx-descriptor status flags
before printing the rx bit rate.
Add a debug message for when a beacon tx buffer reclamation.
Reset IFF_OACTIVE when we reset the transmitter.
Pass the consolidated LED state, a struct rtw_led_state,
to rtw_led_attach.
Choose the bit-rate for management frames (1Mb/s) at the
same place we choose for all other frames.
Do not use the NIC's short preamble or RTS options for
management frames. Label beacons for the NIC.
Following a Linux driver, take care not to zero arbitrary
bits in the TPPOLL register.
Use the new idiom for IBSS merges: disable transmitter,
kick the state machine.
Add a second descriptor to the beacon ring. The NIC seems
to like this much better.
rtw_set_access, rtw_set_access1 to match.
Add a subroutine for setting WEP keys. WEP isn't quite finished,
because I have to add the WEP header to Tx packets. Implement the
SIOCS80211NWKEY ioctl for setting WEP keys.
Program the LEDs based on operating state and packet activity.
* On a Revision F RTL8180, blink LED1 at 1Hz to indicate
scan/authenticate/associate states. In the run state, turn LED1
on. In every state, blink LED1 at 5Hz to indicate non-beacon
tx/rx activity. I would like to use two LEDs, but in all my
Rev. F instances, LED0 is not wired to an LED; instead, the
first LED is wired to indicate that the card's power is on.
* On a Revision D RTL8180, program the LEDs so that LED0 indicates
Tx, and LED1 indicates Rx. The Rx LED will blink annoyingly if
there are beacons in the air, but at least the Tx LED is useful.
* Store the hardware revision in the softc to support my futile
attempt at programming LEDs for both Rev. D and Rev. F parts;
I never did get Rev. D LEDs to work right.
* Add a debug flag RTW_DEBUG_LED for the LED transitions.
Add RTW_TPPOLL_ALL, RTW_TPPOLL_SALL to start and stop, respectively,
all of the transmit rings.
In ad hoc mode, allocate a beacon and load it into the beacon ring.
Start the ring. In one trial, the card re-transmitted the beacon
ring's contents several times before stopping. More programming
and testing for ad hoc mode is necessary. I'm not setting the
beacon flag in the transmit descriptor.
Revamp the transmit section to make better use of all the transmit
rings: beacon queue, high-, low-, and medium-priority rings. Put
beacon frames on the beacon ring. All other management frames,
and data frames, go on the medium-priority ring. Power-save data
frames go on the high-priority ring. (Note that powersaving is
not implemented!) This is a work in progress.
Send all 802.11 Management frames at 1Mbps.
After we put a packet on a transmit ring, tickle the right bit in
the TPPOLL to tell RTL8180. Stop all rings on error and in rtw_stop.
Use the RF chip type, not the RTL8180 revision, to choose between
host- and MAC-controlled RF serial I/O. Now the Netgear MA521
works.
Remove bogus definition of bit RTW_TPPOLL_FSWINT.
Cosmetic: remove two short ladders from rtw_init. Fit the
NIC registers print-out onto one line using the RTW_PRINT_REGS
macro.
sys/dev/ic/rtwvar.h:
Add RTW_PRINT_REGS wrapper macro for rtw_print_regs. It
is a null op unless defined(RTW_DEBUG).
Use clue from rtk(4) and re(4) to fix the rtw(4) packet
filter. Previously, I was using the wrong CRC32 function
to hash multicast addresses; to compensate, I set the
multicast filter to all 1s. Now that I hash the addresses
correctly, I do not any longer set the filter to all 1s.
In rtw_ioctl, avoid gratuitous re-initialization when the
interface flags change. If a !IFF_UP -> IFF_UP transition,
call rtw_init(); otherwise, only reload the packet filter.
In sys/dev/ic/rtwreg.h:
Put useful combinations of Receiver Control Register flags
in RTW_RCR_PKTFILT_MASK, RTW_RCR_MONITOR, and
RTW_RCR_PKTFILT_DEFAULT. (XXX RTW_RCR_MONITOR should be
called RTW_RCR_PKTFILT_MONITOR.)