iPXE
Defines | Functions | Variables
ath5k.c File Reference
#include <stdlib.h>
#include <ipxe/malloc.h>
#include <ipxe/timer.h>
#include <ipxe/netdevice.h>
#include <ipxe/pci.h>
#include <ipxe/pci_io.h>
#include "base.h"
#include "reg.h"

Go to the source code of this file.

Defines

#define ATH5K_CALIB_INTERVAL   10 /* Calibrate PHY every 10 seconds */
#define ATH5K_RETRIES   4 /* Number of times to retry packet sends */
#define ATH5K_DESC_ALIGN   16 /* Alignment for TX/RX descriptors */
#define ATH5K_SPMBL_NO   1
#define ATH5K_SPMBL_YES   2
#define ATH5K_SPMBL_BOTH   3
#define ATH5K_NR_RATES   15

Functions

 FILE_LICENCE (BSD3)
static int ath5k_probe (struct pci_device *pdev)
static void ath5k_remove (struct pci_device *pdev)
static int ath5k_tx (struct net80211_device *dev, struct io_buffer *skb)
static int ath5k_reset (struct ath5k_softc *sc, struct net80211_channel *chan)
static int ath5k_reset_wake (struct ath5k_softc *sc)
static int ath5k_start (struct net80211_device *dev)
static void ath5k_stop (struct net80211_device *dev)
static int ath5k_config (struct net80211_device *dev, int changed)
static void ath5k_poll (struct net80211_device *dev)
static void ath5k_irq (struct net80211_device *dev, int enable)
static int ath5k_attach (struct net80211_device *dev)
static void ath5k_detach (struct net80211_device *dev)
static unsigned int ath5k_copy_channels (struct ath5k_hw *ah, struct net80211_channel *channels, unsigned int mode, unsigned int max)
static int ath5k_setup_bands (struct net80211_device *dev)
static int ath5k_chan_set (struct ath5k_softc *sc, struct net80211_channel *chan)
static void ath5k_setcurmode (struct ath5k_softc *sc, unsigned int mode)
static void ath5k_mode_setup (struct ath5k_softc *sc)
static int ath5k_desc_alloc (struct ath5k_softc *sc)
static void ath5k_desc_free (struct ath5k_softc *sc)
static int ath5k_rxbuf_setup (struct ath5k_softc *sc, struct ath5k_buf *bf)
static int ath5k_txbuf_setup (struct ath5k_softc *sc, struct ath5k_buf *bf)
static void ath5k_txbuf_free (struct ath5k_softc *sc, struct ath5k_buf *bf)
static void ath5k_rxbuf_free (struct ath5k_softc *sc __unused, struct ath5k_buf *bf)
static int ath5k_txq_setup (struct ath5k_softc *sc, int qtype, int subtype)
static void ath5k_txq_drainq (struct ath5k_softc *sc, struct ath5k_txq *txq)
static void ath5k_txq_cleanup (struct ath5k_softc *sc)
static void ath5k_txq_release (struct ath5k_softc *sc)
static int ath5k_rx_start (struct ath5k_softc *sc)
static void ath5k_rx_stop (struct ath5k_softc *sc)
static void ath5k_tx_processq (struct ath5k_softc *sc, struct ath5k_txq *txq)
static int ath5k_init (struct ath5k_softc *sc)
static int ath5k_stop_hw (struct ath5k_softc *sc)
static void ath5k_calibrate (struct ath5k_softc *sc)
static void ath5k_configure_filter (struct ath5k_softc *sc)
static short ath5k_ieee2mhz (short chan)
static int ath5k_hw_rix_to_bitrate (int hw_rix)
int ath5k_bitrate_to_hw_rix (int bitrate)
static struct io_bufferath5k_rx_iob_alloc (struct ath5k_softc *sc, u32 *iob_addr)
static void ath5k_handle_rx (struct ath5k_softc *sc)
static void ath5k_handle_tx (struct ath5k_softc *sc)

Variables

static struct pci_device_id ath5k_nics []
struct {
   u16   bitrate
   u8   short_pmbl
   u8   hw_code
ath5k_rates []
struct pci_driver ath5k_pci_driver __pci_driver
static struct
net80211_device_operations 
ath5k_ops

Define Documentation

#define ATH5K_CALIB_INTERVAL   10 /* Calibrate PHY every 10 seconds */

Definition at line 58 of file ath5k.c.

Referenced by ath5k_poll().

#define ATH5K_RETRIES   4 /* Number of times to retry packet sends */

Definition at line 59 of file ath5k.c.

Referenced by ath5k_txbuf_setup().

#define ATH5K_DESC_ALIGN   16 /* Alignment for TX/RX descriptors */

Definition at line 60 of file ath5k.c.

Referenced by ath5k_desc_alloc().

#define ATH5K_SPMBL_NO   1

Definition at line 88 of file ath5k.c.

Referenced by ath5k_config().

#define ATH5K_SPMBL_YES   2

Definition at line 89 of file ath5k.c.

Referenced by ath5k_config().

#define ATH5K_SPMBL_BOTH   3

Definition at line 90 of file ath5k.c.

#define ATH5K_NR_RATES   15

Definition at line 115 of file ath5k.c.

Referenced by ath5k_bitrate_to_hw_rix(), ath5k_config(), and ath5k_hw_rix_to_bitrate().


Function Documentation

FILE_LICENCE ( BSD3  )
static int ath5k_probe ( struct pci_device pdev) [static]

Definition at line 246 of file ath5k.c.

References adjust_pci_device(), ath5k_softc::ah, ath5k_hw::ah_capabilities, ath5k_hw::ah_mac_srev, ath5k_hw::ah_phy_revision, ath5k_hw::ah_radio_2ghz_revision, ath5k_hw::ah_radio_5ghz_revision, ath5k_hw::ah_single_chip, AR5K_MODE_BIT_11A, AR5K_MODE_BIT_11B, AR5K_VERSION_MAC, AR5K_VERSION_RAD, ath5k_attach(), ath5k_hw_attach(), ath5k_hw_detach(), ATH_STAT_INVALID, ath5k_softc::cachelsz, ath5k_capabilities::cap_mode, net80211_hw_info::channel_change_time, DBG, ath5k_softc::dev, net_device::dev, pci_device_id::driver_data, EIO, ENOMEM, net80211_hw_info::flags, free, ath5k_softc::hwinfo, pci_device::id, ath5k_softc::iobase, ioremap(), iounmap(), pci_device::membase, net80211_alloc(), net80211_free(), net80211_device::netdev, PCI_CACHE_LINE_SIZE, PCI_LATENCY_TIMER, pci_read_config_byte(), pci_set_drvdata(), pci_write_config_byte(), ath5k_softc::pdev, net80211_device::priv, ret, net80211_hw_info::signal_max, net80211_hw_info::signal_type, ath5k_softc::status, and zalloc().

{
        void *mem;
        struct ath5k_softc *sc;
        struct net80211_device *dev;
        int ret;
        u8 csz;

        adjust_pci_device(pdev);

        /*
         * Cache line size is used to size and align various
         * structures used to communicate with the hardware.
         */
        pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &csz);
        if (csz == 0) {
                /*
                 * We must have this setup properly for rx buffer
                 * DMA to work so force a reasonable value here if it
                 * comes up zero.
                 */
                csz = 16;
                pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz);
        }
        /*
         * The default setting of latency timer yields poor results,
         * set it to the value used by other systems.  It may be worth
         * tweaking this setting more.
         */
        pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xa8);

        /*
         * Disable the RETRY_TIMEOUT register (0x41) to keep
         * PCI Tx retries from interfering with C3 CPU state.
         */
        pci_write_config_byte(pdev, 0x41, 0);

        mem = ioremap(pdev->membase, 0x10000);
        if (!mem) {
                DBG("ath5k: cannot remap PCI memory region\n");
                ret = -EIO;
                goto err;
        }

        /*
         * Allocate dev (net80211 main struct)
         * and dev->priv (driver private data)
         */
        dev = net80211_alloc(sizeof(*sc));
        if (!dev) {
                DBG("ath5k: cannot allocate 802.11 device\n");
                ret = -ENOMEM;
                goto err_map;
        }

        /* Initialize driver private data */
        sc = dev->priv;
        sc->dev = dev;
        sc->pdev = pdev;

        sc->hwinfo = zalloc(sizeof(*sc->hwinfo));
        if (!sc->hwinfo) {
                DBG("ath5k: cannot allocate 802.11 hardware info structure\n");
                ret = -ENOMEM;
                goto err_free;
        }

        sc->hwinfo->flags = NET80211_HW_RX_HAS_FCS;
        sc->hwinfo->signal_type = NET80211_SIGNAL_DB;
        sc->hwinfo->signal_max = 40; /* 35dB should give perfect 54Mbps */
        sc->hwinfo->channel_change_time = 5000;

        /* Avoid working with the device until setup is complete */
        sc->status |= ATH_STAT_INVALID;

        sc->iobase = mem;
        sc->cachelsz = csz * 4; /* convert to bytes */

        DBG("ath5k: register base at %p (%08lx)\n", sc->iobase, pdev->membase);
        DBG("ath5k: cache line size %d\n", sc->cachelsz);

        /* Set private data */
        pci_set_drvdata(pdev, dev);
        dev->netdev->dev = (struct device *)pdev;

        /* Initialize device */
        ret = ath5k_hw_attach(sc, pdev->id->driver_data, &sc->ah);
        if (ret)
                goto err_free_hwinfo;

        /* Finish private driver data initialization */
        ret = ath5k_attach(dev);
        if (ret)
                goto err_ah;

#if DBGLVL_MAX
        DBG("Atheros AR%s chip found (MAC: 0x%x, PHY: 0x%x)\n",
            ath5k_chip_name(AR5K_VERSION_MAC, sc->ah->ah_mac_srev),
            sc->ah->ah_mac_srev, sc->ah->ah_phy_revision);

        if (!sc->ah->ah_single_chip) {
                /* Single chip radio (!RF5111) */
                if (sc->ah->ah_radio_5ghz_revision &&
                    !sc->ah->ah_radio_2ghz_revision) {
                        /* No 5GHz support -> report 2GHz radio */
                        if (!(sc->ah->ah_capabilities.cap_mode & AR5K_MODE_BIT_11A)) {
                                DBG("RF%s 2GHz radio found (0x%x)\n",
                                    ath5k_chip_name(AR5K_VERSION_RAD,
                                                    sc->ah->ah_radio_5ghz_revision),
                                    sc->ah->ah_radio_5ghz_revision);
                        /* No 2GHz support (5110 and some
                         * 5Ghz only cards) -> report 5Ghz radio */
                        } else if (!(sc->ah->ah_capabilities.cap_mode & AR5K_MODE_BIT_11B)) {
                                DBG("RF%s 5GHz radio found (0x%x)\n",
                                    ath5k_chip_name(AR5K_VERSION_RAD,
                                                    sc->ah->ah_radio_5ghz_revision),
                                    sc->ah->ah_radio_5ghz_revision);
                        /* Multiband radio */
                        } else {
                                DBG("RF%s multiband radio found (0x%x)\n",
                                    ath5k_chip_name(AR5K_VERSION_RAD,
                                                    sc->ah->ah_radio_5ghz_revision),
                                    sc->ah->ah_radio_5ghz_revision);
                        }
                }
                /* Multi chip radio (RF5111 - RF2111) ->
                 * report both 2GHz/5GHz radios */
                else if (sc->ah->ah_radio_5ghz_revision &&
                         sc->ah->ah_radio_2ghz_revision) {
                        DBG("RF%s 5GHz radio found (0x%x)\n",
                            ath5k_chip_name(AR5K_VERSION_RAD,
                                            sc->ah->ah_radio_5ghz_revision),
                            sc->ah->ah_radio_5ghz_revision);
                        DBG("RF%s 2GHz radio found (0x%x)\n",
                            ath5k_chip_name(AR5K_VERSION_RAD,
                                            sc->ah->ah_radio_2ghz_revision),
                            sc->ah->ah_radio_2ghz_revision);
                }
        }
#endif

        /* Ready to go */
        sc->status &= ~ATH_STAT_INVALID;

        return 0;
err_ah:
        ath5k_hw_detach(sc->ah);
err_free_hwinfo:
        free(sc->hwinfo);
err_free:
        net80211_free(dev);
err_map:
        iounmap(mem);
err:
        return ret;
}
static void ath5k_remove ( struct pci_device pdev) [static]
static int ath5k_tx ( struct net80211_device dev,
struct io_buffer skb 
) [static]

Definition at line 1461 of file ath5k.c.

References ath5k_txbuf_setup(), DBG, ENOBUFS, ath5k_buf::iob, ath5k_buf::list, list_add_tail, list_del, list_empty, list_entry, list_head::next, NULL, net80211_device::priv, rc, ath5k_softc::txbuf, and ath5k_softc::txbuf_len.

{
        struct ath5k_softc *sc = dev->priv;
        struct ath5k_buf *bf;
        int rc;

        /*
         * The hardware expects the header padded to 4 byte boundaries.
         * iPXE only ever sends 24-byte headers, so no action necessary.
         */

        if (list_empty(&sc->txbuf)) {
                DBG("ath5k: dropping packet because no tx bufs available\n");
                return -ENOBUFS;
        }

        bf = list_entry(sc->txbuf.next, struct ath5k_buf, list);
        list_del(&bf->list);
        sc->txbuf_len--;

        bf->iob = iob;

        if ((rc = ath5k_txbuf_setup(sc, bf)) != 0) {
                bf->iob = NULL;
                list_add_tail(&bf->list, &sc->txbuf);
                sc->txbuf_len++;
                return rc;
        }
        return 0;
}
static int ath5k_reset ( struct ath5k_softc sc,
struct net80211_channel chan 
) [static]

Definition at line 1497 of file ath5k.c.

References ath5k_softc::ah, ah, ath5k_hw_reset(), ath5k_hw_set_imr(), ath5k_irq(), ath5k_rx_start(), ath5k_rx_stop(), ath5k_txq_cleanup(), net80211_channel::band, ath5k_softc::curband, ath5k_softc::curchan, DBG, ath5k_softc::dev, ath5k_softc::irq_ena, ret, and strerror().

Referenced by ath5k_chan_set(), ath5k_init(), and ath5k_reset_wake().

{
        struct ath5k_hw *ah = sc->ah;
        int ret;

        if (chan) {
                ath5k_hw_set_imr(ah, 0);
                ath5k_txq_cleanup(sc);
                ath5k_rx_stop(sc);

                sc->curchan = chan;
                sc->curband = chan->band;
        }

        ret = ath5k_hw_reset(ah, sc->curchan, 1);
        if (ret) {
                DBG("ath5k: can't reset hardware: %s\n", strerror(ret));
                return ret;
        }

        ret = ath5k_rx_start(sc);
        if (ret) {
                DBG("ath5k: can't start rx logic: %s\n", strerror(ret));
                return ret;
        }

        /*
         * Change channels and update the h/w rate map if we're switching;
         * e.g. 11a to 11b/g.
         *
         * We may be doing a reset in response to an ioctl that changes the
         * channel so update any state that might change as a result.
         *
         * XXX needed?
         */
/*      ath5k_chan_change(sc, c); */

        /* Reenable interrupts if necessary */
        ath5k_irq(sc->dev, sc->irq_ena);

        return 0;
}
static int ath5k_reset_wake ( struct ath5k_softc sc) [static]

Definition at line 1540 of file ath5k.c.

References ath5k_reset(), and ath5k_softc::curchan.

Referenced by ath5k_calibrate(), and ath5k_poll().

{
        return ath5k_reset(sc, sc->curchan);
}
static int ath5k_start ( struct net80211_device dev) [static]
static void ath5k_stop ( struct net80211_device dev) [static]

Definition at line 1560 of file ath5k.c.

References ath5k_softc::ah, ath5k_hw_set_lladdr(), ath5k_stop_hw(), ETH_ALEN, mac, and net80211_device::priv.

{
        struct ath5k_softc *sc = dev->priv;
        u8 mac[ETH_ALEN] = {};

        ath5k_hw_set_lladdr(sc->ah, mac);

        ath5k_stop_hw(sc);
}
static int ath5k_config ( struct net80211_device dev,
int  changed 
) [static]

Definition at line 1571 of file ath5k.c.

References ath5k_softc::ah, ah, ath5k_hw::ah_bssid, ath5k_softc::assoc, ath5k_chan_set(), ath5k_hw_set_associd(), ATH5K_NR_RATES, ath5k_rates, ATH5K_SPMBL_NO, ATH5K_SPMBL_YES, bitrate, net80211_device::bssid, net80211_device::channel, net80211_device::channels, ETH_ALEN, ath5k_softc::hw_rate, ath5k_softc::hw_rtscts_rate, net80211_channel::maxpower, memcpy(), memset(), NET80211_ASSOCIATED, NET80211_CFG_ASSOC, NET80211_CFG_CHANNEL, NET80211_CFG_PHY_PARAMS, NET80211_CFG_RATE, NET80211_PHY_USE_SHORT_PREAMBLE, net80211_device::phy_flags, ath5k_softc::power_level, net80211_device::priv, net80211_device::rate, net80211_device::rates, ret, net80211_device::rtscts_rate, short_pmbl, and net80211_device::state.

{
        struct ath5k_softc *sc = dev->priv;
        struct ath5k_hw *ah = sc->ah;
        struct net80211_channel *chan = &dev->channels[dev->channel];
        int ret;

        if (changed & NET80211_CFG_CHANNEL) {
                sc->power_level = chan->maxpower;
                if ((ret = ath5k_chan_set(sc, chan)) != 0)
                        return ret;
        }

        if ((changed & NET80211_CFG_RATE) ||
            (changed & NET80211_CFG_PHY_PARAMS)) {
                int spmbl = ATH5K_SPMBL_NO;
                u16 rate = dev->rates[dev->rate];
                u16 slowrate = dev->rates[dev->rtscts_rate];
                int i;

                if (dev->phy_flags & NET80211_PHY_USE_SHORT_PREAMBLE)
                        spmbl = ATH5K_SPMBL_YES;

                for (i = 0; i < ATH5K_NR_RATES; i++) {
                        if (ath5k_rates[i].bitrate == rate &&
                            (ath5k_rates[i].short_pmbl & spmbl))
                                sc->hw_rate = ath5k_rates[i].hw_code;

                        if (ath5k_rates[i].bitrate == slowrate &&
                            (ath5k_rates[i].short_pmbl & spmbl))
                                sc->hw_rtscts_rate = ath5k_rates[i].hw_code;
                }
        }

        if (changed & NET80211_CFG_ASSOC) {
                sc->assoc = !!(dev->state & NET80211_ASSOCIATED);
                if (sc->assoc) {
                        memcpy(ah->ah_bssid, dev->bssid, ETH_ALEN);
                } else {
                        memset(ah->ah_bssid, 0xff, ETH_ALEN);
                }
                ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
        }

        return 0;
}
static void ath5k_poll ( struct net80211_device dev) [static]

Definition at line 1376 of file ath5k.c.

References ath5k_softc::ah, ah, AR5K_INT_FATAL, AR5K_INT_RXEOL, AR5K_INT_RXERR, AR5K_INT_RXOK, AR5K_INT_RXORN, AR5K_INT_TXDESC, AR5K_INT_TXEOL, AR5K_INT_TXERR, AR5K_INT_TXOK, AR5K_INT_TXURN, ATH5K_CALIB_INTERVAL, ath5k_calibrate(), ath5k_handle_rx(), ath5k_handle_tx(), ath5k_hw_get_isr(), ath5k_hw_is_intr_pending(), ath5k_hw_update_tx_triglevel(), ath5k_reset_wake(), ATH_STAT_INVALID, currticks(), DBG, DBGP, ath5k_softc::imask, ath5k_softc::irq_ena, ath5k_softc::last_calib_ticks, NULL, net80211_device::priv, ath5k_softc::rxlink, ath5k_softc::status, status, and TICKS_PER_SEC.

{
        struct ath5k_softc *sc = dev->priv;
        struct ath5k_hw *ah = sc->ah;
        enum ath5k_int status;
        unsigned int counter = 1000;

        if (currticks() - sc->last_calib_ticks >
            ATH5K_CALIB_INTERVAL * TICKS_PER_SEC) {
                ath5k_calibrate(sc);
                sc->last_calib_ticks = currticks();
        }

        if ((sc->status & ATH_STAT_INVALID) ||
            (sc->irq_ena && !ath5k_hw_is_intr_pending(ah)))
                return;

        do {
                ath5k_hw_get_isr(ah, &status);          /* NB: clears IRQ too */
                DBGP("ath5k: status %#x/%#x\n", status, sc->imask);
                if (status & AR5K_INT_FATAL) {
                        /*
                         * Fatal errors are unrecoverable.
                         * Typically these are caused by DMA errors.
                         */
                        DBG("ath5k: fatal error, resetting\n");
                        ath5k_reset_wake(sc);
                } else if (status & AR5K_INT_RXORN) {
                        DBG("ath5k: rx overrun, resetting\n");
                        ath5k_reset_wake(sc);
                } else {
                        if (status & AR5K_INT_RXEOL) {
                                /*
                                 * NB: the hardware should re-read the link when
                                 *     RXE bit is written, but it doesn't work at
                                 *     least on older hardware revs.
                                 */
                                DBG("ath5k: rx EOL\n");
                                sc->rxlink = NULL;
                        }
                        if (status & AR5K_INT_TXURN) {
                                /* bump tx trigger level */
                                DBG("ath5k: tx underrun\n");
                                ath5k_hw_update_tx_triglevel(ah, 1);
                        }
                        if (status & (AR5K_INT_RXOK | AR5K_INT_RXERR))
                                ath5k_handle_rx(sc);
                        if (status & (AR5K_INT_TXOK | AR5K_INT_TXDESC
                                      | AR5K_INT_TXERR | AR5K_INT_TXEOL))
                                ath5k_handle_tx(sc);
                }
        } while (ath5k_hw_is_intr_pending(ah) && counter-- > 0);

        if (!counter)
                DBG("ath5k: too many interrupts, giving up for now\n");
}
static void ath5k_irq ( struct net80211_device dev,
int  enable 
) [static]
static int ath5k_attach ( struct net80211_device dev) [static]

Definition at line 421 of file ath5k.c.

References ath5k_softc::ah, ah, AR5K_MODE_11A, AR5K_MODE_11B, AR5K_MODE_BIT_11A, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_BE, ath5k_desc_alloc(), ath5k_desc_free(), ath5k_eeprom_read_mac(), ath5k_hw_set_bssid_mask(), ath5k_setcurmode(), ath5k_setup_bands(), ath5k_txq_release(), ath5k_txq_setup(), ath5k_softc::bssidmask, currticks(), DBG, ath5k_softc::dev, pci_device::device, ETH_ALEN, net80211_hw_info::hwaddr, ath5k_softc::hwinfo, ath5k_softc::last_calib_ticks, memset(), net80211_register(), ath5k_softc::pdev, net80211_device::priv, and ret.

Referenced by ath5k_probe().

{
        struct ath5k_softc *sc = dev->priv;
        struct ath5k_hw *ah = sc->ah;
        int ret;

        /*
         * Collect the channel list.  The 802.11 layer
         * is resposible for filtering this list based
         * on settings like the phy mode and regulatory
         * domain restrictions.
         */
        ret = ath5k_setup_bands(dev);
        if (ret) {
                DBG("ath5k: can't get channels\n");
                goto err;
        }

        /* NB: setup here so ath5k_rate_update is happy */
        if (ah->ah_modes & AR5K_MODE_BIT_11A)
                ath5k_setcurmode(sc, AR5K_MODE_11A);
        else
                ath5k_setcurmode(sc, AR5K_MODE_11B);

        /*
         * Allocate tx+rx descriptors and populate the lists.
         */
        ret = ath5k_desc_alloc(sc);
        if (ret) {
                DBG("ath5k: can't allocate descriptors\n");
                goto err;
        }

        /*
         * Allocate hardware transmit queues. Note that hw functions
         * handle reseting these queues at the needed time.
         */
        ret = ath5k_txq_setup(sc, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_BE);
        if (ret) {
                DBG("ath5k: can't setup xmit queue\n");
                goto err_desc;
        }

        sc->last_calib_ticks = currticks();

        ret = ath5k_eeprom_read_mac(ah, sc->hwinfo->hwaddr);
        if (ret) {
                DBG("ath5k: unable to read address from EEPROM: 0x%04x\n",
                    sc->pdev->device);
                goto err_queues;
        }

        memset(sc->bssidmask, 0xff, ETH_ALEN);
        ath5k_hw_set_bssid_mask(sc->ah, sc->bssidmask);

        ret = net80211_register(sc->dev, &ath5k_ops, sc->hwinfo);
        if (ret) {
                DBG("ath5k: can't register ieee80211 hw\n");
                goto err_queues;
        }

        return 0;
err_queues:
        ath5k_txq_release(sc);
err_desc:
        ath5k_desc_free(sc);
err:
        return ret;
}
static void ath5k_detach ( struct net80211_device dev) [static]

Definition at line 492 of file ath5k.c.

References ath5k_desc_free(), ath5k_txq_release(), net80211_unregister(), and net80211_device::priv.

Referenced by ath5k_remove().

{
        struct ath5k_softc *sc = dev->priv;

        net80211_unregister(dev);
        ath5k_desc_free(sc);
        ath5k_txq_release(sc);
}
static unsigned int ath5k_copy_channels ( struct ath5k_hw ah,
struct net80211_channel channels,
unsigned int  mode,
unsigned int  max 
) [static]

Definition at line 524 of file ath5k.c.

References AR5K_MODE_11A, AR5K_MODE_11A_TURBO, AR5K_MODE_11B, AR5K_MODE_11G, AR5K_MODE_11G_TURBO, ath5k_channel_ok(), ath5k_ieee2mhz(), net80211_channel::band, net80211_channel::center_freq, ch, CHANNEL_2GHZ, CHANNEL_5GHZ, CHANNEL_B, CHANNEL_OFDM, CHANNEL_TURBO, count, net80211_channel::hw_value, net80211_channel::maxpower, NET80211_BAND_2GHZ, NET80211_BAND_5GHZ, and size.

Referenced by ath5k_setup_bands().

{
        unsigned int i, count, size, chfreq, freq, ch;

        if (!(ah->ah_modes & (1 << mode)))
                return 0;

        switch (mode) {
        case AR5K_MODE_11A:
        case AR5K_MODE_11A_TURBO:
                /* 1..220, but 2GHz frequencies are filtered by check_channel */
                size = 220;
                chfreq = CHANNEL_5GHZ;
                break;
        case AR5K_MODE_11B:
        case AR5K_MODE_11G:
        case AR5K_MODE_11G_TURBO:
                size = 26;
                chfreq = CHANNEL_2GHZ;
                break;
        default:
                return 0;
        }

        for (i = 0, count = 0; i < size && max > 0; i++) {
                ch = i + 1 ;
                freq = ath5k_ieee2mhz(ch);

                /* Check if channel is supported by the chipset */
                if (!ath5k_channel_ok(ah, freq, chfreq))
                        continue;

                /* Write channel info and increment counter */
                channels[count].center_freq = freq;
                channels[count].maxpower = 0; /* use regulatory */
                channels[count].band = (chfreq == CHANNEL_2GHZ) ?
                        NET80211_BAND_2GHZ : NET80211_BAND_5GHZ;
                switch (mode) {
                case AR5K_MODE_11A:
                case AR5K_MODE_11G:
                        channels[count].hw_value = chfreq | CHANNEL_OFDM;
                        break;
                case AR5K_MODE_11A_TURBO:
                case AR5K_MODE_11G_TURBO:
                        channels[count].hw_value = chfreq |
                                CHANNEL_OFDM | CHANNEL_TURBO;
                        break;
                case AR5K_MODE_11B:
                        channels[count].hw_value = CHANNEL_B;
                }

                count++;
                max--;
        }

        return count;
}
static int ath5k_setup_bands ( struct net80211_device dev) [static]

Definition at line 585 of file ath5k.c.

References ath5k_softc::ah, ah, ath5k_hw::ah_capabilities, AR5K_MODE_11B, AR5K_MODE_11G, AR5K_MODE_BIT_11A, AR5K_MODE_BIT_11B, AR5K_MODE_BIT_11G, ath5k_copy_channels(), ath5k_rates, net80211_hw_info::bands, ath5k_capabilities::cap_mode, net80211_hw_info::channels, ath5k_softc::hwinfo, net80211_hw_info::modes, NET80211_BAND_2GHZ, NET80211_BAND_5GHZ, NET80211_BAND_BIT_2GHZ, NET80211_BAND_BIT_5GHZ, NET80211_MODE_A, NET80211_MODE_B, NET80211_MODE_G, net80211_hw_info::nr_channels, net80211_hw_info::nr_rates, net80211_device::priv, and net80211_hw_info::rates.

Referenced by ath5k_attach().

{
        struct ath5k_softc *sc = dev->priv;
        struct ath5k_hw *ah = sc->ah;
        int max_c, count_c = 0;
        int i;
        int band;

        max_c = sizeof(sc->hwinfo->channels) / sizeof(sc->hwinfo->channels[0]);

        /* 2GHz band */
        if (sc->ah->ah_capabilities.cap_mode & AR5K_MODE_BIT_11G) {
                /* G mode */
                band = NET80211_BAND_2GHZ;
                sc->hwinfo->bands = NET80211_BAND_BIT_2GHZ;
                sc->hwinfo->modes = (NET80211_MODE_G | NET80211_MODE_B);

                for (i = 0; i < 12; i++)
                        sc->hwinfo->rates[band][i] = ath5k_rates[i].bitrate;
                sc->hwinfo->nr_rates[band] = 12;

                sc->hwinfo->nr_channels =
                        ath5k_copy_channels(ah, sc->hwinfo->channels,
                                            AR5K_MODE_11G, max_c);
                count_c = sc->hwinfo->nr_channels;
                max_c -= count_c;
        } else if (sc->ah->ah_capabilities.cap_mode & AR5K_MODE_BIT_11B) {
                /* B mode */
                band = NET80211_BAND_2GHZ;
                sc->hwinfo->bands = NET80211_BAND_BIT_2GHZ;
                sc->hwinfo->modes = NET80211_MODE_B;

                for (i = 0; i < 4; i++)
                        sc->hwinfo->rates[band][i] = ath5k_rates[i].bitrate;
                sc->hwinfo->nr_rates[band] = 4;

                sc->hwinfo->nr_channels =
                        ath5k_copy_channels(ah, sc->hwinfo->channels,
                                            AR5K_MODE_11B, max_c);
                count_c = sc->hwinfo->nr_channels;
                max_c -= count_c;
        }

        /* 5GHz band, A mode */
        if (sc->ah->ah_capabilities.cap_mode & AR5K_MODE_BIT_11A) {
                band = NET80211_BAND_5GHZ;
                sc->hwinfo->bands |= NET80211_BAND_BIT_5GHZ;
                sc->hwinfo->modes |= NET80211_MODE_A;

                for (i = 0; i < 8; i++)
                        sc->hwinfo->rates[band][i] = ath5k_rates[i+4].bitrate;
                sc->hwinfo->nr_rates[band] = 8;

                sc->hwinfo->nr_channels =
                        ath5k_copy_channels(ah, sc->hwinfo->channels,
                                            AR5K_MODE_11B, max_c);
                count_c = sc->hwinfo->nr_channels;
                max_c -= count_c;
        }

        return 0;
}
static int ath5k_chan_set ( struct ath5k_softc sc,
struct net80211_channel chan 
) [static]

Definition at line 655 of file ath5k.c.

References ath5k_reset(), net80211_channel::center_freq, ath5k_softc::curchan, DBG2, and net80211_channel::hw_value.

Referenced by ath5k_config().

{
        if (chan->center_freq != sc->curchan->center_freq ||
            chan->hw_value != sc->curchan->hw_value) {
                /*
                 * 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.
                 */
                DBG2("ath5k: resetting for channel change (%d -> %d MHz)\n",
                     sc->curchan->center_freq, chan->center_freq);
                return ath5k_reset(sc, chan);
        }

        return 0;
}
static void ath5k_setcurmode ( struct ath5k_softc sc,
unsigned int  mode 
) [static]

Definition at line 674 of file ath5k.c.

References AR5K_MODE_11A, ath5k_softc::curband, ath5k_softc::curmode, NET80211_BAND_2GHZ, and NET80211_BAND_5GHZ.

Referenced by ath5k_attach().

{
        sc->curmode = mode;

        if (mode == AR5K_MODE_11A) {
                sc->curband = NET80211_BAND_5GHZ;
        } else {
                sc->curband = NET80211_BAND_2GHZ;
        }
}
static void ath5k_mode_setup ( struct ath5k_softc sc) [static]

Definition at line 686 of file ath5k.c.

References ath5k_softc::ah, ah, ath5k_hw_hasbssidmask, ath5k_hw_set_bssid_mask(), ath5k_hw_set_mcast_filter(), ath5k_hw_set_opmode(), ath5k_hw_set_rx_filter(), ath5k_softc::bssidmask, and ath5k_softc::filter_flags.

Referenced by ath5k_rx_start().

{
        struct ath5k_hw *ah = sc->ah;
        u32 rfilt;

        /* configure rx filter */
        rfilt = sc->filter_flags;
        ath5k_hw_set_rx_filter(ah, rfilt);

        if (ath5k_hw_hasbssidmask(ah))
                ath5k_hw_set_bssid_mask(ah, sc->bssidmask);

        /* configure operational mode */
        ath5k_hw_set_opmode(ah);

        ath5k_hw_set_mcast_filter(ah, 0, 0);
}
static int ath5k_desc_alloc ( struct ath5k_softc sc) [static]

Definition at line 870 of file ath5k.c.

References ATH5K_DESC_ALIGN, ATH_RXBUF, ATH_TXBUF, ath5k_softc::bufptr, calloc(), DBG, ath5k_softc::desc, ath5k_softc::desc_daddr, ath5k_softc::desc_len, ds, ENOMEM, free_dma(), INIT_LIST_HEAD, list_add_tail, malloc_dma(), memset(), NULL, ret, ath5k_softc::rxbuf, ath5k_softc::txbuf, ath5k_softc::txbuf_len, and virt_to_bus().

Referenced by ath5k_attach().

{
        struct ath5k_desc *ds;
        struct ath5k_buf *bf;
        u32 da;
        unsigned int i;
        int ret;

        /* allocate descriptors */
        sc->desc_len = sizeof(struct ath5k_desc) * (ATH_TXBUF + ATH_RXBUF + 1);
        sc->desc = malloc_dma(sc->desc_len, ATH5K_DESC_ALIGN);
        if (sc->desc == NULL) {
                DBG("ath5k: can't allocate descriptors\n");
                ret = -ENOMEM;
                goto err;
        }
        memset(sc->desc, 0, sc->desc_len);
        sc->desc_daddr = virt_to_bus(sc->desc);

        ds = sc->desc;
        da = sc->desc_daddr;

        bf = calloc(ATH_TXBUF + ATH_RXBUF + 1, sizeof(struct ath5k_buf));
        if (bf == NULL) {
                DBG("ath5k: can't allocate buffer pointers\n");
                ret = -ENOMEM;
                goto err_free;
        }
        sc->bufptr = bf;

        INIT_LIST_HEAD(&sc->rxbuf);
        for (i = 0; i < ATH_RXBUF; i++, bf++, ds++, da += sizeof(*ds)) {
                bf->desc = ds;
                bf->daddr = da;
                list_add_tail(&bf->list, &sc->rxbuf);
        }

        INIT_LIST_HEAD(&sc->txbuf);
        sc->txbuf_len = ATH_TXBUF;
        for (i = 0; i < ATH_TXBUF; i++, bf++, ds++, da += sizeof(*ds)) {
                bf->desc = ds;
                bf->daddr = da;
                list_add_tail(&bf->list, &sc->txbuf);
        }

        return 0;

err_free:
        free_dma(sc->desc, sc->desc_len);
err:
        sc->desc = NULL;
        return ret;
}
static void ath5k_desc_free ( struct ath5k_softc sc) [static]

Definition at line 925 of file ath5k.c.

References ath5k_rxbuf_free(), ath5k_txbuf_free(), ath5k_softc::bufptr, ath5k_softc::desc, ath5k_softc::desc_len, free, free_dma(), ath5k_buf::list, list_for_each_entry, NULL, ath5k_softc::rxbuf, and ath5k_softc::txbuf.

Referenced by ath5k_attach(), and ath5k_detach().

{
        struct ath5k_buf *bf;

        list_for_each_entry(bf, &sc->txbuf, list)
                ath5k_txbuf_free(sc, bf);
        list_for_each_entry(bf, &sc->rxbuf, list)
                ath5k_rxbuf_free(sc, bf);

        /* Free memory associated with all descriptors */
        free_dma(sc->desc, sc->desc_len);

        free(sc->bufptr);
        sc->bufptr = NULL;
}
static int ath5k_rxbuf_setup ( struct ath5k_softc sc,
struct ath5k_buf bf 
) [static]

Definition at line 770 of file ath5k.c.

References ath5k_softc::ah, ah, ath5k_hw::ah_setup_rx_desc, ath5k_rx_iob_alloc(), ath5k_buf::daddr, DBG, ath5k_buf::desc, ds, ath5k_desc::ds_data, ath5k_desc::ds_link, EINVAL, ENOMEM, ath5k_buf::iob, iob_tailroom(), ath5k_buf::iobaddr, NULL, and ath5k_softc::rxlink.

Referenced by ath5k_handle_rx(), and ath5k_rx_start().

{
        struct ath5k_hw *ah = sc->ah;
        struct io_buffer *iob = bf->iob;
        struct ath5k_desc *ds;

        if (!iob) {
                iob = ath5k_rx_iob_alloc(sc, &bf->iobaddr);
                if (!iob)
                        return -ENOMEM;
                bf->iob = iob;
        }

        /*
         * Setup descriptors.  For receive we always terminate
         * the descriptor list with a self-linked entry so we'll
         * not get overrun under high load (as can happen with a
         * 5212 when ANI processing enables PHY error frames).
         *
         * To insure the last descriptor is self-linked we create
         * each descriptor as self-linked and add it to the end.  As
         * each additional descriptor is added the previous self-linked
         * entry is ``fixed'' naturally.  This should be safe even
         * if DMA is happening.  When processing RX interrupts we
         * never remove/process the last, self-linked, entry on the
         * descriptor list.  This insures the hardware always has
         * someplace to write a new frame.
         */
        ds = bf->desc;
        ds->ds_link = bf->daddr;        /* link to self */
        ds->ds_data = bf->iobaddr;
        if (ah->ah_setup_rx_desc(ah, ds,
                                 iob_tailroom(iob),     /* buffer size */
                                 0) != 0) {
                DBG("ath5k: error setting up RX descriptor for %zd bytes\n", iob_tailroom(iob));
                return -EINVAL;
        }

        if (sc->rxlink != NULL)
                *sc->rxlink = bf->daddr;
        sc->rxlink = &ds->ds_link;
        return 0;
}
static int ath5k_txbuf_setup ( struct ath5k_softc sc,
struct ath5k_buf bf 
) [static]

Definition at line 815 of file ath5k.c.

References ath5k_softc::ah, ah, ath5k_hw::ah_setup_tx_desc, AR5K_PKT_TYPE_NORMAL, AR5K_TXDESC_CLRDMASK, AR5K_TXDESC_CTSENA, AR5K_TXDESC_INTREQ, AR5K_TXKEYIX_INVALID, ath5k_hw_set_txdp(), ath5k_hw_start_tx_dma(), ATH5K_RETRIES, ath5k_buf::daddr, io_buffer::data, ath5k_buf::desc, ath5k_softc::dev, ds, ath5k_desc::ds_data, ath5k_desc::ds_link, duration, flags, ath5k_softc::hw_rate, ath5k_softc::hw_rtscts_rate, IEEE80211_TYP_FRAME_HEADER_LEN, ath5k_buf::iob, iob_len(), ath5k_buf::iobaddr, ath5k_txq::link, ath5k_buf::list, list_add_tail, mb(), net80211_cts_duration(), NET80211_PHY_USE_PROTECTION, NULL, net80211_device::phy_flags, ath5k_softc::power_level, ath5k_txq::q, ath5k_txq::qnum, ret, ath5k_softc::txq, and virt_to_bus().

Referenced by ath5k_tx().

{
        struct ath5k_hw *ah = sc->ah;
        struct ath5k_txq *txq = &sc->txq;
        struct ath5k_desc *ds = bf->desc;
        struct io_buffer *iob = bf->iob;
        unsigned int pktlen, flags;
        int ret;
        u16 duration = 0;
        u16 cts_rate = 0;

        flags = AR5K_TXDESC_INTREQ | AR5K_TXDESC_CLRDMASK;
        bf->iobaddr = virt_to_bus(iob->data);
        pktlen = iob_len(iob);

        /* FIXME: If we are in g mode and rate is a CCK rate
         * subtract ah->ah_txpower.txp_cck_ofdm_pwr_delta
         * from tx power (value is in dB units already) */
        if (sc->dev->phy_flags & NET80211_PHY_USE_PROTECTION) {
                struct net80211_device *dev = sc->dev;

                flags |= AR5K_TXDESC_CTSENA;
                cts_rate = sc->hw_rtscts_rate;
                duration = net80211_cts_duration(dev, pktlen);
        }
        ret = ah->ah_setup_tx_desc(ah, ds, pktlen,
                                   IEEE80211_TYP_FRAME_HEADER_LEN,
                                   AR5K_PKT_TYPE_NORMAL, sc->power_level * 2,
                                   sc->hw_rate, ATH5K_RETRIES,
                                   AR5K_TXKEYIX_INVALID, 0, flags,
                                   cts_rate, duration);
        if (ret)
                return ret;

        ds->ds_link = 0;
        ds->ds_data = bf->iobaddr;

        list_add_tail(&bf->list, &txq->q);
        if (txq->link == NULL) /* is this first packet? */
                ath5k_hw_set_txdp(ah, txq->qnum, bf->daddr);
        else /* no, so only link it */
                *txq->link = bf->daddr;

        txq->link = &ds->ds_link;
        ath5k_hw_start_tx_dma(ah, txq->qnum);
        mb();

        return 0;
}
static void ath5k_txbuf_free ( struct ath5k_softc sc,
struct ath5k_buf bf 
) [inline, static]

Definition at line 178 of file ath5k.c.

References ath5k_softc::dev, ECANCELED, ath5k_buf::iob, net80211_tx_complete(), and NULL.

Referenced by ath5k_desc_free(), and ath5k_txq_drainq().

{
        if (!bf->iob)
                return;

        net80211_tx_complete(sc->dev, bf->iob, 0, ECANCELED);
        bf->iob = NULL;
}
static void ath5k_rxbuf_free ( struct ath5k_softc *sc  __unused,
struct ath5k_buf bf 
) [inline, static]

Definition at line 188 of file ath5k.c.

References free_iob(), ath5k_buf::iob, and NULL.

Referenced by ath5k_desc_free().

{
        free_iob(bf->iob);
        bf->iob = NULL;
}
static int ath5k_txq_setup ( struct ath5k_softc sc,
int  qtype,
int  subtype 
) [static]

Definition at line 950 of file ath5k.c.

References ath5k_softc::ah, ah, AR5K_TXQ_FLAG_TXDESCINT_ENABLE, AR5K_TXQ_FLAG_TXEOLINT_ENABLE, AR5K_TXQ_USEDEFAULT, ath5k_hw_setup_tx_queue(), DBG, EIO, INIT_LIST_HEAD, ath5k_txq::link, NULL, ath5k_txq::q, ath5k_txq::qnum, ath5k_txq::setup, subtype, ath5k_txq_info::tqi_flags, ath5k_txq_info::tqi_subtype, and ath5k_softc::txq.

Referenced by ath5k_attach().

{
        struct ath5k_hw *ah = sc->ah;
        struct ath5k_txq *txq;
        struct ath5k_txq_info qi = {
                .tqi_subtype = subtype,
                .tqi_aifs = AR5K_TXQ_USEDEFAULT,
                .tqi_cw_min = AR5K_TXQ_USEDEFAULT,
                .tqi_cw_max = AR5K_TXQ_USEDEFAULT
        };
        int qnum;

        /*
         * 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.
         */
        qi.tqi_flags = AR5K_TXQ_FLAG_TXEOLINT_ENABLE |
                                AR5K_TXQ_FLAG_TXDESCINT_ENABLE;
        qnum = ath5k_hw_setup_tx_queue(ah, qtype, &qi);
        if (qnum < 0) {
                DBG("ath5k: can't set up a TX queue\n");
                return -EIO;
        }

        txq = &sc->txq;
        if (!txq->setup) {
                txq->qnum = qnum;
                txq->link = NULL;
                INIT_LIST_HEAD(&txq->q);
                txq->setup = 1;
        }
        return 0;
}
static void ath5k_txq_drainq ( struct ath5k_softc sc,
struct ath5k_txq txq 
) [static]
static void ath5k_txq_cleanup ( struct ath5k_softc sc) [static]

Definition at line 1011 of file ath5k.c.

References ath5k_softc::ah, ah, ath5k_hw_get_txdp(), ath5k_hw_stop_tx_dma(), ath5k_txq_drainq(), ATH_STAT_INVALID, DBG, ath5k_txq::link, ath5k_txq::qnum, ath5k_txq::setup, ath5k_softc::status, and ath5k_softc::txq.

Referenced by ath5k_reset(), and ath5k_stop_hw().

{
        struct ath5k_hw *ah = sc->ah;

        if (!(sc->status & ATH_STAT_INVALID)) {
                /* don't touch the hardware if marked invalid */
                if (sc->txq.setup) {
                        ath5k_hw_stop_tx_dma(ah, sc->txq.qnum);
                        DBG("ath5k: txq [%d] %x, link %p\n",
                            sc->txq.qnum,
                            ath5k_hw_get_txdp(ah, sc->txq.qnum),
                            sc->txq.link);
                }
        }

        if (sc->txq.setup)
                ath5k_txq_drainq(sc, &sc->txq);
}
static void ath5k_txq_release ( struct ath5k_softc sc) [static]

Definition at line 1031 of file ath5k.c.

References ath5k_softc::ah, ath5k_hw_release_tx_queue(), ath5k_txq::setup, and ath5k_softc::txq.

Referenced by ath5k_attach(), and ath5k_detach().

{
        if (sc->txq.setup) {
                ath5k_hw_release_tx_queue(sc->ah);
                sc->txq.setup = 0;
        }
}
static int ath5k_rx_start ( struct ath5k_softc sc) [static]

Definition at line 1050 of file ath5k.c.

References ath5k_softc::ah, ah, ath5k_hw_set_rxdp(), ath5k_hw_start_rx_dma(), ath5k_hw_start_rx_pcu(), ath5k_mode_setup(), ath5k_rxbuf_setup(), ath5k_softc::cachelsz, ath5k_buf::daddr, IEEE80211_MAX_LEN, ath5k_buf::list, list_entry, list_for_each_entry, list_head::next, NULL, ret, ath5k_softc::rxbuf, ath5k_softc::rxbufsize, and ath5k_softc::rxlink.

Referenced by ath5k_reset().

{
        struct ath5k_hw *ah = sc->ah;
        struct ath5k_buf *bf;
        int ret;

        sc->rxbufsize = IEEE80211_MAX_LEN;
        if (sc->rxbufsize % sc->cachelsz != 0)
                sc->rxbufsize += sc->cachelsz - (sc->rxbufsize % sc->cachelsz);

        sc->rxlink = NULL;

        list_for_each_entry(bf, &sc->rxbuf, list) {
                ret = ath5k_rxbuf_setup(sc, bf);
                if (ret != 0)
                        return ret;
        }

        bf = list_entry(sc->rxbuf.next, struct ath5k_buf, list);

        ath5k_hw_set_rxdp(ah, bf->daddr);
        ath5k_hw_start_rx_dma(ah);      /* enable recv descriptors */
        ath5k_mode_setup(sc);           /* set filters, etc. */
        ath5k_hw_start_rx_pcu(ah);      /* re-enable PCU/DMA engine */

        return 0;
}
static void ath5k_rx_stop ( struct ath5k_softc sc) [static]

Definition at line 1082 of file ath5k.c.

References ath5k_softc::ah, ah, ath5k_hw_set_rx_filter(), ath5k_hw_stop_rx_dma(), ath5k_hw_stop_rx_pcu(), NULL, and ath5k_softc::rxlink.

Referenced by ath5k_reset(), and ath5k_stop_hw().

{
        struct ath5k_hw *ah = sc->ah;

        ath5k_hw_stop_rx_pcu(ah);       /* disable PCU */
        ath5k_hw_set_rx_filter(ah, 0);  /* clear recv filter */
        ath5k_hw_stop_rx_dma(ah);       /* disable DMA engine */

        sc->rxlink = NULL;              /* just in case */
}
static void ath5k_tx_processq ( struct ath5k_softc sc,
struct ath5k_txq txq 
) [static]

Definition at line 1227 of file ath5k.c.

References ath5k_softc::ah, ath5k_hw::ah_proc_tx_desc, DBG, DBG2, ath5k_buf::desc, ath5k_softc::dev, ds, EINPROGRESS, EIO, ath5k_buf::iob, iob_len(), ath5k_txq::link, io_buffer::list, ath5k_buf::list, list_add_tail, list_del, list_empty, list_for_each_entry_safe, memset(), net80211_tx_complete(), NULL, ath5k_txq::q, ret, strerror(), ath5k_tx_status::ts_retry, ath5k_tx_status::ts_status, ath5k_softc::txbuf, and ath5k_softc::txbuf_len.

Referenced by ath5k_handle_tx().

{
        struct ath5k_tx_status ts;
        struct ath5k_buf *bf, *bf0;
        struct ath5k_desc *ds;
        struct io_buffer *iob;
        int ret;

        memset(&ts, 0, sizeof(ts));

        list_for_each_entry_safe(bf, bf0, &txq->q, list) {
                ds = bf->desc;

                ret = sc->ah->ah_proc_tx_desc(sc->ah, ds, &ts);
                if (ret) {
                        if (ret != -EINPROGRESS) {
                                DBG("ath5k: error in processing tx desc: %s\n",
                                    strerror(ret));
                        } else {
                                /* normal return, reached end of tx completions */
                        }
                        break;
                }

                iob = bf->iob;
                bf->iob = NULL;

                DBG2("ath5k: tx %zd bytes complete, %d retries\n",
                     iob_len(iob), ts.ts_retry[0]);

                net80211_tx_complete(sc->dev, iob, ts.ts_retry[0],
                                     ts.ts_status ? EIO : 0);

                list_del(&bf->list);
                list_add_tail(&bf->list, &sc->txbuf);
                sc->txbuf_len++;
        }

        if (list_empty(&txq->q))
                txq->link = NULL;
}
static int ath5k_init ( struct ath5k_softc sc) [static]

Definition at line 1294 of file ath5k.c.

References ath5k_softc::ah, ah, AR5K_INT_FATAL, AR5K_INT_GLOBAL, AR5K_INT_RXEOL, AR5K_INT_RXERR, AR5K_INT_RXOK, AR5K_INT_RXORN, AR5K_INT_TXDESC, AR5K_INT_TXEOL, AR5K_KEYTABLE_SIZE, ath5k_hw_reset_key(), ath5k_hw_set_ack_bitrate_high(), ath5k_reset(), ath5k_rfkill_hw_start(), ath5k_stop_hw(), net80211_channel::band, net80211_device::channel, net80211_device::channels, ath5k_softc::curband, ath5k_softc::curchan, ath5k_softc::dev, done, ath5k_softc::imask, mb(), NULL, and ret.

Referenced by ath5k_start().

{
        struct ath5k_hw *ah = sc->ah;
        int ret, i;

        /*
         * Stop anything previously setup.  This is safe
         * no matter this is the first time through or not.
         */
        ath5k_stop_hw(sc);

        /*
         * 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.
         */
        sc->curchan = sc->dev->channels + sc->dev->channel;
        sc->curband = sc->curchan->band;
        sc->imask = AR5K_INT_RXOK | AR5K_INT_RXERR | AR5K_INT_RXEOL |
                AR5K_INT_RXORN | AR5K_INT_TXDESC | AR5K_INT_TXEOL |
                AR5K_INT_FATAL | AR5K_INT_GLOBAL;
        ret = ath5k_reset(sc, NULL);
        if (ret)
                goto done;

        ath5k_rfkill_hw_start(ah);

        /*
         * Reset the key cache since some parts do not reset the
         * contents on initial power up or resume from suspend.
         */
        for (i = 0; i < AR5K_KEYTABLE_SIZE; i++)
                ath5k_hw_reset_key(ah, i);

        /* Set ack to be sent at low bit-rates */
        ath5k_hw_set_ack_bitrate_high(ah, 0);

        ret = 0;
done:
        mb();
        return ret;
}
static int ath5k_stop_hw ( struct ath5k_softc sc) [static]

Definition at line 1340 of file ath5k.c.

References ath5k_softc::ah, ah, ath5k_hw_phy_disable(), ath5k_hw_set_imr(), ath5k_rfkill_hw_stop(), ath5k_rx_stop(), ath5k_txq_cleanup(), ATH_STAT_INVALID, NULL, ath5k_softc::rxlink, and ath5k_softc::status.

Referenced by ath5k_init(), and ath5k_stop().

{
        struct ath5k_hw *ah = sc->ah;

        /*
         * Shutdown the hardware and driver:
         *    stop output from above
         *    disable interrupts
         *    turn off timers
         *    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).
         */

        if (!(sc->status & ATH_STAT_INVALID)) {
                ath5k_hw_set_imr(ah, 0);
        }
        ath5k_txq_cleanup(sc);
        if (!(sc->status & ATH_STAT_INVALID)) {
                ath5k_rx_stop(sc);
                ath5k_hw_phy_disable(ah);
        } else
                sc->rxlink = NULL;

        ath5k_rfkill_hw_stop(sc->ah);

        return 0;
}
static void ath5k_calibrate ( struct ath5k_softc sc) [static]

Definition at line 1438 of file ath5k.c.

References ath5k_softc::ah, ah, AR5K_RFGAIN_NEED_CHANGE, ath5k_hw_gainf_calibrate(), ath5k_hw_phy_calibrate(), ath5k_reset_wake(), net80211_channel::channel_nr, ath5k_softc::curchan, and DBG.

Referenced by ath5k_poll().

{
        struct ath5k_hw *ah = sc->ah;

        if (ath5k_hw_gainf_calibrate(ah) == AR5K_RFGAIN_NEED_CHANGE) {
                /*
                 * Rfgain is out of bounds, reset the chip
                 * to load new gain values.
                 */
                DBG("ath5k: resetting for calibration\n");
                ath5k_reset_wake(sc);
        }
        if (ath5k_hw_phy_calibrate(ah, sc->curchan))
                DBG("ath5k: calibration of channel %d failed\n",
                    sc->curchan->channel_nr);
}
static void ath5k_configure_filter ( struct ath5k_softc sc) [static]

Definition at line 1636 of file ath5k.c.

References ath5k_softc::ah, ah, AR5K_RX_FILTER_BCAST, AR5K_RX_FILTER_BEACON, AR5K_RX_FILTER_MCAST, AR5K_RX_FILTER_UCAST, ath5k_hw_set_mcast_filter(), ath5k_hw_set_rx_filter(), and ath5k_softc::filter_flags.

Referenced by ath5k_start().

{
        struct ath5k_hw *ah = sc->ah;
        u32 mfilt[2], rfilt;

        /* Enable all multicast */
        mfilt[0] = ~0;
        mfilt[1] = ~0;

        /* Enable data frames and beacons */
        rfilt = (AR5K_RX_FILTER_UCAST | AR5K_RX_FILTER_BCAST |
                 AR5K_RX_FILTER_MCAST | AR5K_RX_FILTER_BEACON);

        /* Set filters */
        ath5k_hw_set_rx_filter(ah, rfilt);

        /* Set multicast bits */
        ath5k_hw_set_mcast_filter(ah, mfilt[0], mfilt[1]);

        /* Set the cached hw filter flags, this will alter actually
         * be set in HW */
        sc->filter_flags = rfilt;
}
static short ath5k_ieee2mhz ( short  chan) [inline, static]

Definition at line 512 of file ath5k.c.

Referenced by ath5k_copy_channels().

{
        if (chan < 14)
                return 2407 + 5 * chan;
        if (chan == 14)
                return 2484;
        if (chan < 27)
                return 2212 + 20 * chan;
        return 5000 + 5 * chan;
}
static int ath5k_hw_rix_to_bitrate ( int  hw_rix) [inline, static]

Definition at line 705 of file ath5k.c.

References ATH5K_NR_RATES, ath5k_rates, DBG, and hw_code.

Referenced by ath5k_handle_rx().

{
        int i;

        for (i = 0; i < ATH5K_NR_RATES; i++) {
                if (ath5k_rates[i].hw_code == hw_rix)
                        return ath5k_rates[i].bitrate;
        }

        DBG("ath5k: invalid rix %02x\n", hw_rix);
        return 10;              /* use lowest rate */
}
int ath5k_bitrate_to_hw_rix ( int  bitrate)

Definition at line 718 of file ath5k.c.

References ATH5K_NR_RATES, ATH5K_RATE_CODE_1M, ath5k_rates, and DBG.

Referenced by ath5k_hw_write_rate_duration().

{
        int i;

        for (i = 0; i < ATH5K_NR_RATES; i++) {
                if (ath5k_rates[i].bitrate == bitrate)
                        return ath5k_rates[i].hw_code;
        }

        DBG("ath5k: invalid bitrate %d\n", bitrate);
        return ATH5K_RATE_CODE_1M; /* use lowest rate */
}
static struct io_buffer* ath5k_rx_iob_alloc ( struct ath5k_softc sc,
u32 iob_addr 
) [static, read]

Definition at line 736 of file ath5k.c.

References alloc_iob(), ath5k_softc::cachelsz, io_buffer::data, DBG, iob_reserve, NULL, ath5k_softc::rxbufsize, and virt_to_bus().

Referenced by ath5k_handle_rx(), and ath5k_rxbuf_setup().

{
        struct io_buffer *iob;
        unsigned int off;

        /*
         * Allocate buffer with headroom_needed space for the
         * fake physical layer header at the start.
         */
        iob = alloc_iob(sc->rxbufsize + sc->cachelsz - 1);

        if (!iob) {
                DBG("ath5k: can't alloc iobuf of size %d\n",
                    sc->rxbufsize + sc->cachelsz - 1);
                return NULL;
        }

        *iob_addr = virt_to_bus(iob->data);

        /*
         * Cache-line-align.  This is important (for the
         * 5210 at least) as not doing so causes bogus data
         * in rx'd frames.
         */
        off = *iob_addr % sc->cachelsz;
        if (off != 0) {
                iob_reserve(iob, sc->cachelsz - off);
                *iob_addr += sc->cachelsz - off;
        }

        return iob;
}
static void ath5k_handle_rx ( struct ath5k_softc sc) [static]

Definition at line 1094 of file ath5k.c.

References ath5k_softc::ah, ath5k_hw::ah_proc_rx_desc, AR5K_RXERR_CRC, AR5K_RXERR_DECRYPT, AR5K_RXERR_PHY, AR5K_RXKEYIX_INVALID, assert, ath5k_hw_rix_to_bitrate(), ath5k_rx_iob_alloc(), ath5k_rxbuf_setup(), DBG, DBG2, ath5k_buf::desc, ath5k_softc::dev, ds, EINPROGRESS, EIO, ath5k_buf::flags, ath5k_buf::iob, iob_put, ath5k_buf::iobaddr, ath5k_buf::list, list_add_tail, list_del, list_empty, list_entry, memset(), net80211_rx(), net80211_rx_err(), list_head::next, next, NULL, list_head::prev, ret, ath5k_rx_status::rs_datalen, ath5k_rx_status::rs_keyix, ath5k_rx_status::rs_more, ath5k_rx_status::rs_rate, ath5k_rx_status::rs_rssi, ath5k_rx_status::rs_status, ath5k_softc::rxbuf, and strerror().

Referenced by ath5k_poll().

{
        struct ath5k_rx_status rs;
        struct io_buffer *iob, *next_iob;
        u32 next_iob_addr;
        struct ath5k_buf *bf, *bf_last;
        struct ath5k_desc *ds;
        int ret;

        memset(&rs, 0, sizeof(rs));

        if (list_empty(&sc->rxbuf)) {
                DBG("ath5k: empty rx buf pool\n");
                return;
        }

        bf_last = list_entry(sc->rxbuf.prev, struct ath5k_buf, list);

        do {
                bf = list_entry(sc->rxbuf.next, struct ath5k_buf, list);
                assert(bf->iob != NULL);
                iob = bf->iob;
                ds = bf->desc;

                /*
                 * last buffer must not be freed to ensure proper hardware
                 * function. When the hardware finishes also a packet next to
                 * it, we are sure, it doesn't use it anymore and we can go on.
                 */
                if (bf_last == bf)
                        bf->flags |= 1;
                if (bf->flags) {
                        struct ath5k_buf *bf_next = list_entry(bf->list.next,
                                        struct ath5k_buf, list);
                        ret = sc->ah->ah_proc_rx_desc(sc->ah, bf_next->desc,
                                        &rs);
                        if (ret)
                                break;
                        bf->flags &= ~1;
                        /* skip the overwritten one (even status is martian) */
                        goto next;
                }

                ret = sc->ah->ah_proc_rx_desc(sc->ah, ds, &rs);
                if (ret) {
                        if (ret != -EINPROGRESS) {
                                DBG("ath5k: error in processing rx desc: %s\n",
                                    strerror(ret));
                                net80211_rx_err(sc->dev, NULL, -ret);
                        } else {
                                /* normal return, reached end of
                                   available descriptors */
                        }
                        return;
                }

                if (rs.rs_more) {
                        DBG("ath5k: unsupported fragmented rx\n");
                        goto next;
                }

                if (rs.rs_status) {
                        if (rs.rs_status & AR5K_RXERR_PHY) {
                                /* These are uncommon, and may indicate a real problem. */
                                net80211_rx_err(sc->dev, NULL, EIO);
                                goto next;
                        }
                        if (rs.rs_status & AR5K_RXERR_CRC) {
                                /* These occur *all the time*. */
                                goto next;
                        }
                        if (rs.rs_status & AR5K_RXERR_DECRYPT) {
                                /*
                                 * Decrypt error.  If the error occurred
                                 * because there was no hardware key, then
                                 * let the frame through so the upper layers
                                 * can process it.  This is necessary for 5210
                                 * parts which have no way to setup a ``clear''
                                 * key cache entry.
                                 *
                                 * XXX do key cache faulting
                                 */
                                if (rs.rs_keyix == AR5K_RXKEYIX_INVALID &&
                                    !(rs.rs_status & AR5K_RXERR_CRC))
                                        goto accept;
                        }

                        /* any other error, unhandled */
                        DBG("ath5k: packet rx status %x\n", rs.rs_status);
                        goto next;
                }
accept:
                next_iob = ath5k_rx_iob_alloc(sc, &next_iob_addr);

                /*
                 * If we can't replace bf->iob with a new iob under memory
                 * pressure, just skip this packet
                 */
                if (!next_iob) {
                        DBG("ath5k: dropping packet under memory pressure\n");
                        goto next;
                }

                iob_put(iob, rs.rs_datalen);

                /* The MAC header is padded to have 32-bit boundary if the
                 * packet payload is non-zero. However, iPXE only
                 * supports standard 802.11 packets with 24-byte
                 * header, so no padding correction should be needed.
                 */

                DBG2("ath5k: rx %d bytes, signal %d\n", rs.rs_datalen,
                     rs.rs_rssi);

                net80211_rx(sc->dev, iob, rs.rs_rssi,
                            ath5k_hw_rix_to_bitrate(rs.rs_rate));

                bf->iob = next_iob;
                bf->iobaddr = next_iob_addr;
next:
                list_del(&bf->list);
                list_add_tail(&bf->list, &sc->rxbuf);
        } while (ath5k_rxbuf_setup(sc, bf) == 0);
}
static void ath5k_handle_tx ( struct ath5k_softc sc) [static]

Definition at line 1270 of file ath5k.c.

References ath5k_tx_processq(), and ath5k_softc::txq.

Referenced by ath5k_poll().

{
        ath5k_tx_processq(sc, &sc->txq);
}

Variable Documentation

struct pci_device_id ath5k_nics[] [static]
Initial value:
 {
        PCI_ROM(0x168c, 0x0207, "ath5210e", "Atheros 5210 early", AR5K_AR5210),
        PCI_ROM(0x168c, 0x0007, "ath5210", "Atheros 5210", AR5K_AR5210),
        PCI_ROM(0x168c, 0x0011, "ath5311", "Atheros 5311 (AHB)", AR5K_AR5211),
        PCI_ROM(0x168c, 0x0012, "ath5211", "Atheros 5211", AR5K_AR5211),
        PCI_ROM(0x168c, 0x0013, "ath5212", "Atheros 5212", AR5K_AR5212),
        PCI_ROM(0xa727, 0x0013, "ath5212c","3com Ath 5212", AR5K_AR5212),
        PCI_ROM(0x10b7, 0x0013, "rdag675", "3com 3CRDAG675", AR5K_AR5212),
        PCI_ROM(0x168c, 0x1014, "ath5212m", "Ath 5212 miniPCI", AR5K_AR5212),
        PCI_ROM(0x168c, 0x0014, "ath5212x14", "Atheros 5212 x14", AR5K_AR5212),
        PCI_ROM(0x168c, 0x0015, "ath5212x15", "Atheros 5212 x15", AR5K_AR5212),
        PCI_ROM(0x168c, 0x0016, "ath5212x16", "Atheros 5212 x16", AR5K_AR5212),
        PCI_ROM(0x168c, 0x0017, "ath5212x17", "Atheros 5212 x17", AR5K_AR5212),
        PCI_ROM(0x168c, 0x0018, "ath5212x18", "Atheros 5212 x18", AR5K_AR5212),
        PCI_ROM(0x168c, 0x0019, "ath5212x19", "Atheros 5212 x19", AR5K_AR5212),
        PCI_ROM(0x168c, 0x001a, "ath2413", "Atheros 2413 Griffin", AR5K_AR5212),
        PCI_ROM(0x168c, 0x001b, "ath5413", "Atheros 5413 Eagle", AR5K_AR5212),
        PCI_ROM(0x168c, 0x001c, "ath5212e", "Atheros 5212 PCI-E", AR5K_AR5212),
        PCI_ROM(0x168c, 0x001d, "ath2417", "Atheros 2417 Nala", AR5K_AR5212),
}

Definition at line 67 of file ath5k.c.

Definition at line 93 of file ath5k.c.

Referenced by ath5k_config().

Definition at line 94 of file ath5k.c.

Referenced by ath5k_config().

Definition at line 95 of file ath5k.c.

Referenced by ath5k_hw_rix_to_bitrate().

struct { ... } ath5k_rates[] [static]
struct pci_driver ath5k_pci_driver __pci_driver
Initial value:
 {
        .ids            = ath5k_nics,
        .id_count       = sizeof(ath5k_nics) / sizeof(ath5k_nics[0]),
        .probe          = ath5k_probe,
        .remove         = ath5k_remove,
}

Definition at line 123 of file ath5k.c.

Initial value:
 {
        .open           = ath5k_start,
        .close          = ath5k_stop,
        .transmit       = ath5k_tx,
        .poll           = ath5k_poll,
        .irq            = ath5k_irq,
        .config         = ath5k_config,
}

Definition at line 144 of file ath5k.c.