summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorweongyo <weongyo@FreeBSD.org>2008-03-25 06:32:33 +0000
committerweongyo <weongyo@FreeBSD.org>2008-03-25 06:32:33 +0000
commit9a9594d179e3c5f3f47d805d0479f17ee4475f84 (patch)
treeb93f9a4683497d690c51a5b90df665ddeb05a595
parent953e13c915c537826014e9efb6bc8a4009727f72 (diff)
downloadFreeBSD-src-9a9594d179e3c5f3f47d805d0479f17ee4475f84.zip
FreeBSD-src-9a9594d179e3c5f3f47d805d0479f17ee4475f84.tar.gz
Add support for Marvell Libertas 88W8335 based PCI network adapters.
Reviewed by: sam, many wireless people Approved by: thompsa (mentor)
-rw-r--r--share/man/man4/malo.4124
-rw-r--r--sys/dev/malo/if_malo.c2472
-rw-r--r--sys/dev/malo/if_malo.h586
-rw-r--r--sys/dev/malo/if_malo_pci.c373
-rw-r--r--sys/dev/malo/if_malohal.c918
-rw-r--r--sys/dev/malo/if_malohal.h234
-rw-r--r--sys/dev/malo/if_maloioctl.h114
-rw-r--r--sys/modules/malo/Makefile8
8 files changed, 4829 insertions, 0 deletions
diff --git a/share/man/man4/malo.4 b/share/man/man4/malo.4
new file mode 100644
index 0000000..7a9ec8d
--- /dev/null
+++ b/share/man/man4/malo.4
@@ -0,0 +1,124 @@
+.\"-
+.\" Copyright (c) 2008 Weongyo Jeong <weongyo@freebsd.org>
+.\" All rights reserved.
+.\""
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer,
+.\" without modification.
+.\" 2. Redistributions in binary form must reproduce at minimum a disclaimer
+.\" similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+.\" redistribution must be conditioned upon including a substantially
+.\" similar Disclaimer requirement for further binary redistribution.
+.\" 3. Neither the names of the above-listed copyright holders nor the names
+.\" of any contributors may be used to endorse or promote products derived
+.\" from this software without specific prior written permission.
+.\"
+.\" NO WARRANTY
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+.\" LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+.\" AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+.\" THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+.\" OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+.\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+.\" THE POSSIBILITY OF SUCH DAMAGES.
+.\"
+.\" $FreeBSD$
+.\"/
+.Dd February 18 2008
+.Dt MALO 4
+.Os
+.Sh NAME
+.Nm malo
+.Nd "Marvell Libertas IEEE 802.11b/g wireless network device"
+.Sh SYNOPSIS
+To compile this driver into the kernel,
+place the following lines in your
+kernel configuration file:
+.Bd -ragged -offset indent
+.Cd "device malo"
+.Cd "device pci"
+.Cd "device wlan"
+.Cd "device firmware"
+.Ed
+.Pp
+Alternatively, to load the driver as a
+module at boot time, place the following lines in
+.Xr loader.conf 5 :
+.Bd -literal -offset indent
+if_malo_load="YES"
+wlan_load="YES"
+firmware_load="YES"
+.Ed
+.Pp
+In both cases, place the following lines in
+.Xr loader.conf 5
+to load the firmware modules:
+.Bd -literal -offset indent
+malofw_load="YES"
+.Ed
+.Sh DESCRIPTION
+The
+.Nm
+driver provides support for Marvell Libertas 88W8335 based PCI
+network adapters.
+.Sh FILES
+The driver needs a firmware kernel module which is used when
+an interface is brought up. This firmware files are comed from
+.Ox
+.Nm
+driver.
+.Pp
+A port package for the firmware can be found at:
+.Bd -literal -offset indent
+http://weongyo.org/project/malo/malo-firmware-1.4.tar.gz
+.Ed
+.Pp
+You need to install this port package manually before
+.Xr ifconfig 8
+will work.
+.Sh HARDWARE
+The following cards are among those supported by the
+.Nm
+driver:
+.Pp
+.Bl -column -compact "Microcom Travelcard" "MALO111" "CardBus" "a/b/g" -offset 6n
+.Em "Card Chip Bus Standard"
+Netgear WG311v3 88W8335 PCI b/g
+Tenda TWL542P 88W8335 PCI b/g
+U-Khan UW-2054i 88W8335 PCI b/g
+.El
+.Sh EXAMPLES
+Join an existing BSS network (ie: connect to an access point):
+.Pp
+.Dl "ifconfig malo0 inet 192.168.0.20 netmask 0xffffff00"
+.Pp
+Join a specific BSS network with network name
+.Dq Li my_net :
+.Pp
+.Dl "ifconfig malo0 inet 192.168.0.20 netmask 0xffffff00 ssid my_net"
+.Pp
+Join a specific BSS network with WEP encryption:
+.Bd -literal -offset indent
+ifconfig malo0 inet 192.168.0.20 netmask 0xffffff00 ssid my_net \e
+ wepmode on wepkey 0x8736639624
+.Ed
+.Sh SEE ALSO
+.Xr altq 4 ,
+.Xr arp 4 ,
+.Xr cardbus 4 ,
+.Xr netintro 4 ,
+.Xr pci 4 ,
+.Xr wlan 4 ,
+.Xr ifconfig 8
+.Sh HISTORY
+The
+.Nm
+device driver first appeared in
+.Fx 8.0 .
diff --git a/sys/dev/malo/if_malo.c b/sys/dev/malo/if_malo.c
new file mode 100644
index 0000000..a1a6285
--- /dev/null
+++ b/sys/dev/malo/if_malo.c
@@ -0,0 +1,2472 @@
+/*-
+ * Copyright (c) 2008 Weongyo Jeong <weongyo@freebsd.org>
+ * Copyright (c) 2007 Marvell Semiconductor, Inc.
+ * Copyright (c) 2007 Sam Leffler, Errno Consulting
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ * redistribution must be conditioned upon including a substantially
+ * similar Disclaimer requirement for further binary redistribution.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <sys/cdefs.h>
+#ifdef __FreeBSD__
+__FBSDID("$FreeBSD$");
+#endif
+
+#include <sys/param.h>
+#include <sys/endian.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/sysctl.h>
+#include <sys/taskqueue.h>
+
+#include <machine/bus.h>
+#include <sys/bus.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+#include <net/ethernet.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_regdomain.h>
+
+#include <net/bpf.h>
+
+#include <dev/malo/if_malo.h>
+
+SYSCTL_NODE(_hw, OID_AUTO, malo, CTLFLAG_RD, 0,
+ "Marvell 88w8335 driver parameters");
+
+static int malo_txcoalesce = 8; /* # tx pkts to q before poking f/w*/
+SYSCTL_INT(_hw_malo, OID_AUTO, txcoalesce, CTLFLAG_RW, &malo_txcoalesce,
+ 0, "tx buffers to send at once");
+TUNABLE_INT("hw.malo.txcoalesce", &malo_txcoalesce);
+static int malo_rxbuf = MALO_RXBUF; /* # rx buffers to allocate */
+SYSCTL_INT(_hw_malo, OID_AUTO, rxbuf, CTLFLAG_RW, &malo_rxbuf,
+ 0, "rx buffers allocated");
+TUNABLE_INT("hw.malo.rxbuf", &malo_rxbuf);
+static int malo_rxquota = MALO_RXBUF; /* # max buffers to process */
+SYSCTL_INT(_hw_malo, OID_AUTO, rxquota, CTLFLAG_RW, &malo_rxquota,
+ 0, "max rx buffers to process per interrupt");
+TUNABLE_INT("hw.malo.rxquota", &malo_rxquota);
+static int malo_txbuf = MALO_TXBUF; /* # tx buffers to allocate */
+SYSCTL_INT(_hw_malo, OID_AUTO, txbuf, CTLFLAG_RW, &malo_txbuf,
+ 0, "tx buffers allocated");
+TUNABLE_INT("hw.malo.txbuf", &malo_txbuf);
+
+#ifdef MALO_DEBUG
+static int malo_debug = 0;
+SYSCTL_INT(_hw_malo, OID_AUTO, debug, CTLFLAG_RW, &malo_debug,
+ 0, "control debugging printfs");
+TUNABLE_INT("hw.malo.debug", &malo_debug);
+enum {
+ MALO_DEBUG_XMIT = 0x00000001, /* basic xmit operation */
+ MALO_DEBUG_XMIT_DESC = 0x00000002, /* xmit descriptors */
+ MALO_DEBUG_RECV = 0x00000004, /* basic recv operation */
+ MALO_DEBUG_RECV_DESC = 0x00000008, /* recv descriptors */
+ MALO_DEBUG_RESET = 0x00000010, /* reset processing */
+ MALO_DEBUG_INTR = 0x00000040, /* ISR */
+ MALO_DEBUG_TX_PROC = 0x00000080, /* tx ISR proc */
+ MALO_DEBUG_RX_PROC = 0x00000100, /* rx ISR proc */
+ MALO_DEBUG_STATE = 0x00000400, /* 802.11 state transitions */
+ MALO_DEBUG_NODE = 0x00000800, /* node management */
+ MALO_DEBUG_RECV_ALL = 0x00001000, /* trace all frames (beacons) */
+ MALO_DEBUG_FW = 0x00008000, /* firmware */
+ MALO_DEBUG_ANY = 0xffffffff
+};
+#define IS_BEACON(wh) \
+ ((wh->i_fc[0] & (IEEE80211_FC0_TYPE_MASK | \
+ IEEE80211_FC0_SUBTYPE_MASK)) == \
+ (IEEE80211_FC0_TYPE_MGT|IEEE80211_FC0_SUBTYPE_BEACON))
+#define IFF_DUMPPKTS_RECV(sc, wh) \
+ (((sc->malo_debug & MALO_DEBUG_RECV) && \
+ ((sc->malo_debug & MALO_DEBUG_RECV_ALL) || !IS_BEACON(wh))) || \
+ (sc->malo_ifp->if_flags & (IFF_DEBUG|IFF_LINK2)) == \
+ (IFF_DEBUG|IFF_LINK2))
+#define IFF_DUMPPKTS_XMIT(sc) \
+ ((sc->malo_debug & MALO_DEBUG_XMIT) || \
+ (sc->malo_ifp->if_flags & (IFF_DEBUG | IFF_LINK2)) == \
+ (IFF_DEBUG | IFF_LINK2))
+#define DPRINTF(sc, m, fmt, ...) do { \
+ if (sc->malo_debug & (m)) \
+ printf(fmt, __VA_ARGS__); \
+} while (0)
+#else
+#define DPRINTF(sc, m, fmt, ...) do { \
+ (void) sc; \
+} while (0)
+#endif
+
+MALLOC_DEFINE(M_MALODEV, "malodev", "malo driver dma buffers");
+
+static int malo_dma_setup(struct malo_softc *);
+static int malo_setup_hwdma(struct malo_softc *);
+static void malo_txq_init(struct malo_softc *, struct malo_txq *, int);
+static void malo_tx_cleanupq(struct malo_softc *, struct malo_txq *);
+static void malo_start(struct ifnet *);
+static void malo_watchdog(struct ifnet *);
+static int malo_ioctl(struct ifnet *, u_long, caddr_t);
+static void malo_updateslot(struct ifnet *);
+static int malo_newstate(struct ieee80211com *, enum ieee80211_state, int);
+static void malo_scan_start(struct ieee80211com *);
+static void malo_scan_end(struct ieee80211com *);
+static void malo_set_channel(struct ieee80211com *);
+static int malo_raw_xmit(struct ieee80211_node *, struct mbuf *,
+ const struct ieee80211_bpf_params *);
+static int malo_media_change(struct ifnet *);
+static void malo_bpfattach(struct malo_softc *);
+static void malo_sysctlattach(struct malo_softc *);
+static void malo_announce(struct malo_softc *);
+static void malo_dma_cleanup(struct malo_softc *);
+static void malo_stop_locked(struct ifnet *, int);
+static int malo_chan_set(struct malo_softc *, struct ieee80211_channel *);
+static int malo_mode_init(struct malo_softc *);
+static void malo_tx_proc(void *, int);
+static void malo_rx_proc(void *, int);
+static void malo_init(void *);
+
+/*
+ * Read/Write shorthands for accesses to BAR 0. Note that all BAR 1
+ * operations are done in the "hal" except getting H/W MAC address at
+ * malo_attach and there should be no reference to them here.
+ */
+static uint32_t
+malo_bar0_read4(struct malo_softc *sc, bus_size_t off)
+{
+ return bus_space_read_4(sc->malo_io0t, sc->malo_io0h, off);
+}
+
+static void
+malo_bar0_write4(struct malo_softc *sc, bus_size_t off, uint32_t val)
+{
+ DPRINTF(sc, MALO_DEBUG_FW, "%s: off 0x%x val 0x%x\n",
+ __func__, off, val);
+
+ bus_space_write_4(sc->malo_io0t, sc->malo_io0h, off, val);
+}
+
+static uint8_t
+malo_bar1_read1(struct malo_softc *sc, bus_size_t off)
+{
+ return bus_space_read_1(sc->malo_io1t, sc->malo_io1h, off);
+}
+
+int
+malo_attach(uint16_t devid, struct malo_softc *sc)
+{
+ int error, i;
+ struct ieee80211com *ic = &sc->malo_ic;
+ struct ifnet *ifp;
+ struct malo_hal *mh;
+ uint8_t bands;
+
+ ifp = sc->malo_ifp = if_alloc(IFT_ETHER);
+ if (ifp == NULL) {
+ device_printf(sc->malo_dev, "can not if_alloc()\n");
+ return ENOSPC;
+ }
+
+ MALO_LOCK_INIT(sc);
+
+ /* set these up early for if_printf use */
+ if_initname(ifp, device_get_name(sc->malo_dev),
+ device_get_unit(sc->malo_dev));
+
+ /*
+ * NB: get mac address from hardware directly here before we set DMAs
+ * for HAL because we don't want to disturb operations of HAL at BAR 1.
+ */
+ for (i = 0; i < IEEE80211_ADDR_LEN; i++) {
+ /* XXX remove a magic number but we don't have documents. */
+ ic->ic_myaddr[i] = malo_bar1_read1(sc, 0xa528 + i);
+ DELAY(1000);
+ }
+
+ mh = malo_hal_attach(sc->malo_dev, devid,
+ sc->malo_io1h, sc->malo_io1t, sc->malo_dmat);
+ if (mh == NULL) {
+ if_printf(ifp, "unable to attach HAL\n");
+ error = EIO;
+ goto bad;
+ }
+ sc->malo_mh = mh;
+
+ sc->malo_txantenna = 0x2; /* h/w default */
+ sc->malo_rxantenna = 0xffff; /* h/w default */
+
+ /*
+ * Allocate tx + rx descriptors and populate the lists.
+ * We immediately push the information to the firmware
+ * as otherwise it gets upset.
+ */
+ error = malo_dma_setup(sc);
+ if (error != 0) {
+ if_printf(ifp, "failed to setup descriptors: %d\n", error);
+ goto bad1;
+ }
+
+ sc->malo_tq = taskqueue_create_fast("malo_taskq", M_NOWAIT,
+ taskqueue_thread_enqueue, &sc->malo_tq);
+ taskqueue_start_threads(&sc->malo_tq, 1, PI_NET,
+ "%s taskq", ifp->if_xname);
+
+ TASK_INIT(&sc->malo_rxtask, 0, malo_rx_proc, sc);
+ TASK_INIT(&sc->malo_txtask, 0, malo_tx_proc, sc);
+
+ ifp->if_softc = sc;
+ ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST;
+ ifp->if_start = malo_start;
+ ifp->if_watchdog = malo_watchdog;
+ ifp->if_ioctl = malo_ioctl;
+ ifp->if_init = malo_init;
+ IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
+ ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN;
+ IFQ_SET_READY(&ifp->if_snd);
+
+ /* NB: firmware looks that it does not export regdomain info API. */
+ bands = 0;
+ setbit(&bands, IEEE80211_MODE_11B);
+ setbit(&bands, IEEE80211_MODE_11G);
+ ieee80211_init_channels(ic, 0, CTRY_DEFAULT, bands, 0, 1);
+
+ ic->ic_ifp = ifp;
+ /* XXX not right but it's not used anywhere important */
+ ic->ic_phytype = IEEE80211_T_OFDM;
+ ic->ic_opmode = IEEE80211_M_STA;
+ ic->ic_caps =
+ IEEE80211_C_BGSCAN /* capable of bg scanning */
+ | IEEE80211_C_MONITOR /* monitor mode */
+ | IEEE80211_C_SHPREAMBLE /* short preamble supported */
+ | IEEE80211_C_SHSLOT /* short slot time supported */
+ | IEEE80211_C_TXPMGT /* capable of txpow mgt */
+ | IEEE80211_C_WPA /* capable of WPA1+WPA2 */
+ ;
+
+ /*
+ * Transmit requires space in the packet for a special format transmit
+ * record and optional padding between this record and the payload.
+ * Ask the net80211 layer to arrange this when encapsulating
+ * packets so we can add it efficiently.
+ */
+ ic->ic_headroom = sizeof(struct malo_txrec) -
+ sizeof(struct ieee80211_frame);
+
+ /* call MI attach routine. */
+ ieee80211_ifattach(ic);
+ /* override default methods */
+ ic->ic_updateslot = malo_updateslot;
+ ic->ic_raw_xmit = malo_raw_xmit;
+
+ sc->malo_newstate = ic->ic_newstate;
+ ic->ic_newstate = malo_newstate;
+
+ ic->ic_scan_start = malo_scan_start;
+ ic->ic_scan_end = malo_scan_end;
+ ic->ic_set_channel = malo_set_channel;
+
+ /* complete initialization */
+ ieee80211_media_init(ic, malo_media_change, ieee80211_media_status);
+
+ sc->malo_invalid = 0; /* ready to go, enable int handling */
+
+ malo_bpfattach(sc);
+
+ /*
+ * Setup dynamic sysctl's.
+ */
+ malo_sysctlattach(sc);
+
+ if (bootverbose)
+ ieee80211_announce(ic);
+
+ return 0;
+bad1:
+ malo_hal_detach(mh);
+bad:
+ if_free(ifp);
+ sc->malo_invalid = 1;
+
+ return error;
+}
+
+int
+malo_intr(void *arg)
+{
+ struct malo_softc *sc = arg;
+ struct malo_hal *mh = sc->malo_mh;
+ uint32_t status;
+
+ if (sc->malo_invalid) {
+ /*
+ * The hardware is not ready/present, don't touch anything.
+ * Note this can happen early on if the IRQ is shared.
+ */
+ DPRINTF(sc, MALO_DEBUG_ANY, "%s: invalid; ignored\n", __func__);
+ return (FILTER_STRAY);
+ }
+
+ /*
+ * Figure out the reason(s) for the interrupt.
+ */
+ malo_hal_getisr(mh, &status); /* NB: clears ISR too */
+ if (status == 0) /* must be a shared irq */
+ return (FILTER_STRAY);
+
+ DPRINTF(sc, MALO_DEBUG_INTR, "%s: status 0x%x imask 0x%x\n",
+ __func__, status, sc->malo_imask);
+
+ if (status & MALO_A2HRIC_BIT_RX_RDY)
+ taskqueue_enqueue_fast(sc->malo_tq, &sc->malo_rxtask);
+ if (status & MALO_A2HRIC_BIT_TX_DONE)
+ taskqueue_enqueue_fast(sc->malo_tq, &sc->malo_txtask);
+ if (status & MALO_A2HRIC_BIT_OPC_DONE)
+ malo_hal_cmddone(mh);
+ if (status & MALO_A2HRIC_BIT_MAC_EVENT)
+ ;
+ if (status & MALO_A2HRIC_BIT_RX_PROBLEM)
+ ;
+ if (status & MALO_A2HRIC_BIT_ICV_ERROR) {
+ /* TKIP ICV error */
+ sc->malo_stats.mst_rx_badtkipicv++;
+ }
+
+#ifdef MALO_DEBUG
+ if (((status | sc->malo_imask) ^ sc->malo_imask) != 0)
+ DPRINTF(sc, MALO_DEBUG_INTR,
+ "%s: can't handle interrupt status 0x%x\n",
+ __func__, status);
+#endif
+
+ return (FILTER_HANDLED);
+}
+
+static void
+malo_load_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
+{
+ bus_addr_t *paddr = (bus_addr_t*) arg;
+
+ KASSERT(error == 0, ("error %u on bus_dma callback", error));
+
+ *paddr = segs->ds_addr;
+}
+
+static int
+malo_desc_setup(struct malo_softc *sc, const char *name,
+ struct malo_descdma *dd,
+ int nbuf, size_t bufsize, int ndesc, size_t descsize)
+{
+ int error;
+ struct ifnet *ifp = sc->malo_ifp;
+ uint8_t *ds;
+
+ DPRINTF(sc, MALO_DEBUG_RESET,
+ "%s: %s DMA: %u bufs (%ju) %u desc/buf (%ju)\n",
+ __func__, name, nbuf, (uintmax_t) bufsize,
+ ndesc, (uintmax_t) descsize);
+
+ dd->dd_name = name;
+ dd->dd_desc_len = nbuf * ndesc * descsize;
+
+ /*
+ * Setup DMA descriptor area.
+ */
+ error = bus_dma_tag_create(bus_get_dma_tag(sc->malo_dev),/* parent */
+ PAGE_SIZE, 0, /* alignment, bounds */
+ BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ dd->dd_desc_len, /* maxsize */
+ 1, /* nsegments */
+ dd->dd_desc_len, /* maxsegsize */
+ BUS_DMA_ALLOCNOW, /* flags */
+ NULL, /* lockfunc */
+ NULL, /* lockarg */
+ &dd->dd_dmat);
+ if (error != 0) {
+ if_printf(ifp, "cannot allocate %s DMA tag\n", dd->dd_name);
+ return error;
+ }
+
+ /* allocate descriptors */
+ error = bus_dmamap_create(dd->dd_dmat, BUS_DMA_NOWAIT, &dd->dd_dmamap);
+ if (error != 0) {
+ if_printf(ifp, "unable to create dmamap for %s descriptors, "
+ "error %u\n", dd->dd_name, error);
+ goto fail0;
+ }
+
+ error = bus_dmamem_alloc(dd->dd_dmat, (void**) &dd->dd_desc,
+ BUS_DMA_NOWAIT | BUS_DMA_COHERENT, &dd->dd_dmamap);
+ if (error != 0) {
+ if_printf(ifp, "unable to alloc memory for %u %s descriptors, "
+ "error %u\n", nbuf * ndesc, dd->dd_name, error);
+ goto fail1;
+ }
+
+ error = bus_dmamap_load(dd->dd_dmat, dd->dd_dmamap,
+ dd->dd_desc, dd->dd_desc_len,
+ malo_load_cb, &dd->dd_desc_paddr, BUS_DMA_NOWAIT);
+ if (error != 0) {
+ if_printf(ifp, "unable to map %s descriptors, error %u\n",
+ dd->dd_name, error);
+ goto fail2;
+ }
+
+ ds = dd->dd_desc;
+ memset(ds, 0, dd->dd_desc_len);
+ DPRINTF(sc, MALO_DEBUG_RESET, "%s: %s DMA map: %p (%lu) -> %p (%lu)\n",
+ __func__, dd->dd_name, ds, (u_long) dd->dd_desc_len,
+ (caddr_t) dd->dd_desc_paddr, /*XXX*/ (u_long) dd->dd_desc_len);
+
+ return 0;
+fail2:
+ bus_dmamem_free(dd->dd_dmat, dd->dd_desc, dd->dd_dmamap);
+fail1:
+ bus_dmamap_destroy(dd->dd_dmat, dd->dd_dmamap);
+fail0:
+ bus_dma_tag_destroy(dd->dd_dmat);
+ memset(dd, 0, sizeof(*dd));
+ return error;
+}
+
+#define DS2PHYS(_dd, _ds) \
+ ((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc))
+
+static int
+malo_rxdma_setup(struct malo_softc *sc)
+{
+ struct ifnet *ifp = sc->malo_ifp;
+ int error, bsize, i;
+ struct malo_rxbuf *bf;
+ struct malo_rxdesc *ds;
+
+ error = malo_desc_setup(sc, "rx", &sc->malo_rxdma,
+ malo_rxbuf, sizeof(struct malo_rxbuf),
+ 1, sizeof(struct malo_rxdesc));
+ if (error != 0)
+ return error;
+
+ /*
+ * Allocate rx buffers and set them up.
+ */
+ bsize = malo_rxbuf * sizeof(struct malo_rxbuf);
+ bf = malloc(bsize, M_MALODEV, M_NOWAIT | M_ZERO);
+ if (bf == NULL) {
+ if_printf(ifp, "malloc of %u rx buffers failed\n", bsize);
+ return error;
+ }
+ sc->malo_rxdma.dd_bufptr = bf;
+
+ STAILQ_INIT(&sc->malo_rxbuf);
+ ds = sc->malo_rxdma.dd_desc;
+ for (i = 0; i < malo_rxbuf; i++, bf++, ds++) {
+ bf->bf_desc = ds;
+ bf->bf_daddr = DS2PHYS(&sc->malo_rxdma, ds);
+ error = bus_dmamap_create(sc->malo_dmat, BUS_DMA_NOWAIT,
+ &bf->bf_dmamap);
+ if (error != 0) {
+ if_printf(ifp, "%s: unable to dmamap for rx buffer, "
+ "error %d\n", __func__, error);
+ return error;
+ }
+ /* NB: tail is intentional to preserve descriptor order */
+ STAILQ_INSERT_TAIL(&sc->malo_rxbuf, bf, bf_list);
+ }
+ return 0;
+}
+
+static int
+malo_txdma_setup(struct malo_softc *sc, struct malo_txq *txq)
+{
+ struct ifnet *ifp = sc->malo_ifp;
+ int error, bsize, i;
+ struct malo_txbuf *bf;
+ struct malo_txdesc *ds;
+
+ error = malo_desc_setup(sc, "tx", &txq->dma,
+ malo_txbuf, sizeof(struct malo_txbuf),
+ MALO_TXDESC, sizeof(struct malo_txdesc));
+ if (error != 0)
+ return error;
+
+ /* allocate and setup tx buffers */
+ bsize = malo_txbuf * sizeof(struct malo_txbuf);
+ bf = malloc(bsize, M_MALODEV, M_NOWAIT | M_ZERO);
+ if (bf == NULL) {
+ if_printf(ifp, "malloc of %u tx buffers failed\n",
+ malo_txbuf);
+ return ENOMEM;
+ }
+ txq->dma.dd_bufptr = bf;
+
+ STAILQ_INIT(&txq->free);
+ txq->nfree = 0;
+ ds = txq->dma.dd_desc;
+ for (i = 0; i < malo_txbuf; i++, bf++, ds += MALO_TXDESC) {
+ bf->bf_desc = ds;
+ bf->bf_daddr = DS2PHYS(&txq->dma, ds);
+ error = bus_dmamap_create(sc->malo_dmat, BUS_DMA_NOWAIT,
+ &bf->bf_dmamap);
+ if (error != 0) {
+ if_printf(ifp, "unable to create dmamap for tx "
+ "buffer %u, error %u\n", i, error);
+ return error;
+ }
+ STAILQ_INSERT_TAIL(&txq->free, bf, bf_list);
+ txq->nfree++;
+ }
+
+ return 0;
+}
+
+static void
+malo_desc_cleanup(struct malo_softc *sc, struct malo_descdma *dd)
+{
+ bus_dmamap_unload(dd->dd_dmat, dd->dd_dmamap);
+ bus_dmamem_free(dd->dd_dmat, dd->dd_desc, dd->dd_dmamap);
+ bus_dmamap_destroy(dd->dd_dmat, dd->dd_dmamap);
+ bus_dma_tag_destroy(dd->dd_dmat);
+
+ memset(dd, 0, sizeof(*dd));
+}
+
+static void
+malo_rxdma_cleanup(struct malo_softc *sc)
+{
+ struct malo_rxbuf *bf;
+
+ STAILQ_FOREACH(bf, &sc->malo_rxbuf, bf_list) {
+ if (bf->bf_m != NULL) {
+ m_freem(bf->bf_m);
+ bf->bf_m = NULL;
+ }
+ if (bf->bf_dmamap != NULL) {
+ bus_dmamap_destroy(sc->malo_dmat, bf->bf_dmamap);
+ bf->bf_dmamap = NULL;
+ }
+ }
+ STAILQ_INIT(&sc->malo_rxbuf);
+ if (sc->malo_rxdma.dd_bufptr != NULL) {
+ free(sc->malo_rxdma.dd_bufptr, M_MALODEV);
+ sc->malo_rxdma.dd_bufptr = NULL;
+ }
+ if (sc->malo_rxdma.dd_desc_len != 0)
+ malo_desc_cleanup(sc, &sc->malo_rxdma);
+}
+
+static void
+malo_txdma_cleanup(struct malo_softc *sc, struct malo_txq *txq)
+{
+ struct malo_txbuf *bf;
+ struct ieee80211_node *ni;
+
+ STAILQ_FOREACH(bf, &txq->free, bf_list) {
+ if (bf->bf_m != NULL) {
+ m_freem(bf->bf_m);
+ bf->bf_m = NULL;
+ }
+ ni = bf->bf_node;
+ bf->bf_node = NULL;
+ if (ni != NULL) {
+ /*
+ * Reclaim node reference.
+ */
+ ieee80211_free_node(ni);
+ }
+ if (bf->bf_dmamap != NULL) {
+ bus_dmamap_destroy(sc->malo_dmat, bf->bf_dmamap);
+ bf->bf_dmamap = NULL;
+ }
+ }
+ STAILQ_INIT(&txq->free);
+ txq->nfree = 0;
+ if (txq->dma.dd_bufptr != NULL) {
+ free(txq->dma.dd_bufptr, M_MALODEV);
+ txq->dma.dd_bufptr = NULL;
+ }
+ if (txq->dma.dd_desc_len != 0)
+ malo_desc_cleanup(sc, &txq->dma);
+}
+
+static void
+malo_dma_cleanup(struct malo_softc *sc)
+{
+ int i;
+
+ for (i = 0; i < MALO_NUM_TX_QUEUES; i++)
+ malo_txdma_cleanup(sc, &sc->malo_txq[i]);
+
+ malo_rxdma_cleanup(sc);
+}
+
+static int
+malo_dma_setup(struct malo_softc *sc)
+{
+ int error, i;
+
+ /* rxdma initializing. */
+ error = malo_rxdma_setup(sc);
+ if (error != 0)
+ return error;
+
+ /* NB: we just have 1 tx queue now. */
+ for (i = 0; i < MALO_NUM_TX_QUEUES; i++) {
+ error = malo_txdma_setup(sc, &sc->malo_txq[i]);
+ if (error != 0) {
+ malo_dma_cleanup(sc);
+
+ return error;
+ }
+
+ malo_txq_init(sc, &sc->malo_txq[i], i);
+ }
+
+ return 0;
+}
+
+static void
+malo_hal_set_rxtxdma(struct malo_softc *sc)
+{
+ int i;
+
+ malo_bar0_write4(sc, sc->malo_hwspecs.rxdesc_read,
+ sc->malo_hwdma.rxdesc_read);
+ malo_bar0_write4(sc, sc->malo_hwspecs.rxdesc_write,
+ sc->malo_hwdma.rxdesc_read);
+
+ for (i = 0; i < MALO_NUM_TX_QUEUES; i++) {
+ malo_bar0_write4(sc,
+ sc->malo_hwspecs.wcbbase[i], sc->malo_hwdma.wcbbase[i]);
+ }
+}
+
+/*
+ * Inform firmware of our tx/rx dma setup. The BAR 0 writes below are
+ * for compatibility with older firmware. For current firmware we send
+ * this information with a cmd block via malo_hal_sethwdma.
+ */
+static int
+malo_setup_hwdma(struct malo_softc *sc)
+{
+ int i;
+ struct malo_txq *txq;
+
+ sc->malo_hwdma.rxdesc_read = sc->malo_rxdma.dd_desc_paddr;
+
+ for (i = 0; i < MALO_NUM_TX_QUEUES; i++) {
+ txq = &sc->malo_txq[i];
+ sc->malo_hwdma.wcbbase[i] = txq->dma.dd_desc_paddr;
+ }
+ sc->malo_hwdma.maxnum_txwcb = malo_txbuf;
+ sc->malo_hwdma.maxnum_wcb = MALO_NUM_TX_QUEUES;
+
+ malo_hal_set_rxtxdma(sc);
+
+ return 0;
+}
+
+static void
+malo_txq_init(struct malo_softc *sc, struct malo_txq *txq, int qnum)
+{
+ struct malo_txbuf *bf, *bn;
+ struct malo_txdesc *ds;
+
+ MALO_TXQ_LOCK_INIT(sc, txq);
+ txq->qnum = qnum;
+ txq->txpri = 0; /* XXX */
+
+ STAILQ_FOREACH(bf, &txq->free, bf_list) {
+ bf->bf_txq = txq;
+
+ ds = bf->bf_desc;
+ bn = STAILQ_NEXT(bf, bf_list);
+ if (bn == NULL)
+ bn = STAILQ_FIRST(&txq->free);
+ ds->physnext = htole32(bn->bf_daddr);
+ }
+ STAILQ_INIT(&txq->active);
+}
+
+/*
+ * Reclaim resources for a setup queue.
+ */
+static void
+malo_tx_cleanupq(struct malo_softc *sc, struct malo_txq *txq)
+{
+ /* XXX hal work? */
+ MALO_TXQ_LOCK_DESTROY(txq);
+}
+
+/*
+ * Allocate a tx buffer for sending a frame.
+ */
+static struct malo_txbuf *
+malo_getbuf(struct malo_softc *sc, struct malo_txq *txq)
+{
+ struct malo_txbuf *bf;
+
+ MALO_TXQ_LOCK(txq);
+ bf = STAILQ_FIRST(&txq->free);
+ if (bf != NULL) {
+ STAILQ_REMOVE_HEAD(&txq->free, bf_list);
+ txq->nfree--;
+ }
+ MALO_TXQ_UNLOCK(txq);
+ if (bf == NULL) {
+ DPRINTF(sc, MALO_DEBUG_XMIT,
+ "%s: out of xmit buffers on q %d\n", __func__, txq->qnum);
+ sc->malo_stats.mst_tx_qstop++;
+ }
+ return bf;
+}
+
+static int
+malo_tx_dmasetup(struct malo_softc *sc, struct malo_txbuf *bf, struct mbuf *m0)
+{
+ struct mbuf *m;
+ int error;
+
+ /*
+ * Load the DMA map so any coalescing is done. This also calculates
+ * the number of descriptors we need.
+ */
+ error = bus_dmamap_load_mbuf_sg(sc->malo_dmat, bf->bf_dmamap, m0,
+ bf->bf_segs, &bf->bf_nseg,
+ BUS_DMA_NOWAIT);
+ if (error == EFBIG) {
+ /* XXX packet requires too many descriptors */
+ bf->bf_nseg = MALO_TXDESC + 1;
+ } else if (error != 0) {
+ sc->malo_stats.mst_tx_busdma++;
+ m_freem(m0);
+ return error;
+ }
+ /*
+ * Discard null packets and check for packets that require too many
+ * TX descriptors. We try to convert the latter to a cluster.
+ */
+ if (error == EFBIG) { /* too many desc's, linearize */
+ sc->malo_stats.mst_tx_linear++;
+ m = m_defrag(m0, M_DONTWAIT);
+ if (m == NULL) {
+ m_freem(m0);
+ sc->malo_stats.mst_tx_nombuf++;
+ return ENOMEM;
+ }
+ m0 = m;
+ error = bus_dmamap_load_mbuf_sg(sc->malo_dmat, bf->bf_dmamap, m0,
+ bf->bf_segs, &bf->bf_nseg,
+ BUS_DMA_NOWAIT);
+ if (error != 0) {
+ sc->malo_stats.mst_tx_busdma++;
+ m_freem(m0);
+ return error;
+ }
+ KASSERT(bf->bf_nseg <= MALO_TXDESC,
+ ("too many segments after defrag; nseg %u", bf->bf_nseg));
+ } else if (bf->bf_nseg == 0) { /* null packet, discard */
+ sc->malo_stats.mst_tx_nodata++;
+ m_freem(m0);
+ return EIO;
+ }
+ DPRINTF(sc, MALO_DEBUG_XMIT, "%s: m %p len %u\n",
+ __func__, m0, m0->m_pkthdr.len);
+ bus_dmamap_sync(sc->malo_dmat, bf->bf_dmamap, BUS_DMASYNC_PREWRITE);
+ bf->bf_m = m0;
+
+ return 0;
+}
+
+#ifdef MALO_DEBUG
+static void
+malo_printrxbuf(const struct malo_rxbuf *bf, u_int ix)
+{
+ const struct malo_rxdesc *ds = bf->bf_desc;
+ uint32_t status = le32toh(ds->status);
+
+ printf("R[%2u] (DS.V:%p DS.P:%p) NEXT:%08x DATA:%08x RC:%02x%s\n"
+ " STAT:%02x LEN:%04x SNR:%02x NF:%02x CHAN:%02x"
+ " RATE:%02x QOS:%04x\n",
+ ix, ds, (const struct malo_desc *)bf->bf_daddr,
+ le32toh(ds->physnext), le32toh(ds->physbuffdata),
+ ds->rxcontrol,
+ ds->rxcontrol != MALO_RXD_CTRL_DRIVER_OWN ?
+ "" : (status & MALO_RXD_STATUS_OK) ? " *" : " !",
+ ds->status, le16toh(ds->pktlen), ds->snr, ds->nf, ds->channel,
+ ds->rate, le16toh(ds->qosctrl));
+}
+
+static void
+malo_printtxbuf(const struct malo_txbuf *bf, u_int qnum, u_int ix)
+{
+ const struct malo_txdesc *ds = bf->bf_desc;
+ uint32_t status = le32toh(ds->status);
+
+ printf("Q%u[%3u]", qnum, ix);
+ printf(" (DS.V:%p DS.P:%p)\n",
+ ds, (const struct malo_txdesc *)bf->bf_daddr);
+ printf(" NEXT:%08x DATA:%08x LEN:%04x STAT:%08x%s\n",
+ le32toh(ds->physnext),
+ le32toh(ds->pktptr), le16toh(ds->pktlen), status,
+ status & MALO_TXD_STATUS_USED ?
+ "" : (status & 3) != 0 ? " *" : " !");
+ printf(" RATE:%02x PRI:%x QOS:%04x SAP:%08x FORMAT:%04x\n",
+ ds->datarate, ds->txpriority, le16toh(ds->qosctrl),
+ le32toh(ds->sap_pktinfo), le16toh(ds->format));
+#if 0
+ {
+ const uint8_t *cp = (const uint8_t *) ds;
+ int i;
+ for (i = 0; i < sizeof(struct malo_txdesc); i++) {
+ printf("%02x ", cp[i]);
+ if (((i+1) % 16) == 0)
+ printf("\n");
+ }
+ printf("\n");
+ }
+#endif
+}
+#endif /* MALO_DEBUG */
+
+static __inline void
+malo_updatetxrate(struct ieee80211_node *ni, int rix)
+{
+#define N(x) (sizeof(x)/sizeof(x[0]))
+ static const int ieeerates[] =
+ { 2, 4, 11, 22, 44, 12, 18, 24, 36, 48, 96, 108 };
+ if (rix < N(ieeerates))
+ ni->ni_txrate = ieeerates[rix];
+#undef N
+}
+
+static int
+malo_fix2rate(int fix_rate)
+{
+#define N(x) (sizeof(x)/sizeof(x[0]))
+ static const int rates[] =
+ { 2, 4, 11, 22, 12, 18, 24, 36, 48, 96, 108 };
+ return (fix_rate < N(rates) ? rates[fix_rate] : 0);
+#undef N
+}
+
+/* idiomatic shorthands: MS = mask+shift, SM = shift+mask */
+#define MS(v,x) (((v) & x) >> x##_S)
+#define SM(v,x) (((v) << x##_S) & x)
+
+/*
+ * Process completed xmit descriptors from the specified queue.
+ */
+static int
+malo_tx_processq(struct malo_softc *sc, struct malo_txq *txq)
+{
+ struct malo_txbuf *bf;
+ struct malo_txdesc *ds;
+ struct ieee80211_node *ni;
+ int nreaped;
+ uint32_t status;
+
+ DPRINTF(sc, MALO_DEBUG_TX_PROC, "%s: tx queue %u\n",
+ __func__, txq->qnum);
+ for (nreaped = 0;; nreaped++) {
+ MALO_TXQ_LOCK(txq);
+ bf = STAILQ_FIRST(&txq->active);
+ if (bf == NULL) {
+ MALO_TXQ_UNLOCK(txq);
+ break;
+ }
+ ds = bf->bf_desc;
+ MALO_TXDESC_SYNC(txq, ds,
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+ if (ds->status & htole32(MALO_TXD_STATUS_FW_OWNED)) {
+ MALO_TXQ_UNLOCK(txq);
+ break;
+ }
+ STAILQ_REMOVE_HEAD(&txq->active, bf_list);
+ MALO_TXQ_UNLOCK(txq);
+
+#ifdef MALO_DEBUG
+ if (sc->malo_debug & MALO_DEBUG_XMIT_DESC)
+ malo_printtxbuf(bf, txq->qnum, nreaped);
+#endif
+ ni = bf->bf_node;
+ if (ni != NULL) {
+ status = le32toh(ds->status);
+ if (status & MALO_TXD_STATUS_OK) {
+ uint16_t format = le16toh(ds->format);
+ uint8_t txant = MS(format, MALO_TXD_ANTENNA);
+
+ sc->malo_stats.mst_ant_tx[txant]++;
+ if (status & MALO_TXD_STATUS_OK_RETRY)
+ sc->malo_stats.mst_tx_retries++;
+ if (status & MALO_TXD_STATUS_OK_MORE_RETRY)
+ sc->malo_stats.mst_tx_mretries++;
+ malo_updatetxrate(ni, ds->datarate);
+ sc->malo_stats.mst_tx_rate = ds->datarate;
+ } else {
+ if (status & MALO_TXD_STATUS_FAILED_LINK_ERROR)
+ sc->malo_stats.mst_tx_linkerror++;
+ if (status & MALO_TXD_STATUS_FAILED_XRETRY)
+ sc->malo_stats.mst_tx_xretries++;
+ if (status & MALO_TXD_STATUS_FAILED_AGING)
+ sc->malo_stats.mst_tx_aging++;
+ }
+ /*
+ * Do any tx complete callback. Note this must
+ * be done before releasing the node reference.
+ * XXX no way to figure out if frame was ACK'd
+ */
+ if (bf->bf_m->m_flags & M_TXCB) {
+ /* XXX strip fw len in case header inspected */
+ m_adj(bf->bf_m, sizeof(uint16_t));
+ ieee80211_process_callback(ni, bf->bf_m,
+ (status & MALO_TXD_STATUS_OK) == 0);
+ }
+ /*
+ * Reclaim reference to node.
+ *
+ * NB: the node may be reclaimed here if, for example
+ * this is a DEAUTH message that was sent and the
+ * node was timed out due to inactivity.
+ */
+ ieee80211_free_node(ni);
+ }
+ ds->status = htole32(MALO_TXD_STATUS_IDLE);
+ ds->pktlen = htole32(0);
+
+ bus_dmamap_sync(sc->malo_dmat, bf->bf_dmamap,
+ BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(sc->malo_dmat, bf->bf_dmamap);
+ m_freem(bf->bf_m);
+ bf->bf_m = NULL;
+ bf->bf_node = NULL;
+
+ MALO_TXQ_LOCK(txq);
+ STAILQ_INSERT_TAIL(&txq->free, bf, bf_list);
+ txq->nfree++;
+ MALO_TXQ_UNLOCK(txq);
+ }
+ return nreaped;
+}
+
+/*
+ * Deferred processing of transmit interrupt.
+ */
+static void
+malo_tx_proc(void *arg, int npending)
+{
+ struct malo_softc *sc = arg;
+ struct ifnet *ifp = sc->malo_ifp;
+ int i, nreaped;
+
+ /*
+ * Process each active queue.
+ */
+ nreaped = 0;
+ for (i = 0; i < MALO_NUM_TX_QUEUES; i++) {
+ if (!STAILQ_EMPTY(&sc->malo_txq[i].active))
+ nreaped += malo_tx_processq(sc, &sc->malo_txq[i]);
+ }
+
+ if (nreaped != 0) {
+ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+ ifp->if_timer = 0;
+ malo_start(ifp);
+ }
+}
+
+static int
+malo_tx_start(struct malo_softc *sc, struct ieee80211_node *ni,
+ struct malo_txbuf *bf, struct mbuf *m0)
+{
+#define IEEE80211_DIR_DSTODS(wh) \
+ ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS)
+#define IS_DATA_FRAME(wh) \
+ ((wh->i_fc[0] & (IEEE80211_FC0_TYPE_MASK)) == IEEE80211_FC0_TYPE_DATA)
+ int error, ismcast, iswep;
+ int copyhdrlen, hdrlen, pktlen;
+ struct ieee80211_frame *wh;
+ struct ieee80211com *ic = &sc->malo_ic;
+ struct ifnet *ifp = sc->malo_ifp;
+ struct malo_txdesc *ds;
+ struct malo_txrec *tr;
+ struct malo_txq *txq;
+ uint16_t qos;
+
+ wh = mtod(m0, struct ieee80211_frame *);
+ iswep = wh->i_fc[1] & IEEE80211_FC1_WEP;
+ ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1);
+ copyhdrlen = hdrlen = ieee80211_anyhdrsize(wh);
+ pktlen = m0->m_pkthdr.len;
+ if (IEEE80211_QOS_HAS_SEQ(wh)) {
+ if (IEEE80211_DIR_DSTODS(wh)) {
+ qos = *(uint16_t *)
+ (((struct ieee80211_qosframe_addr4 *) wh)->i_qos);
+ copyhdrlen -= sizeof(qos);
+ } else
+ qos = *(uint16_t *)
+ (((struct ieee80211_qosframe *) wh)->i_qos);
+ } else
+ qos = 0;
+
+ if (iswep) {
+ struct ieee80211_key *k;
+
+ /*
+ * Construct the 802.11 header+trailer for an encrypted
+ * frame. The only reason this can fail is because of an
+ * unknown or unsupported cipher/key type.
+ *
+ * NB: we do this even though the firmware will ignore
+ * what we've done for WEP and TKIP as we need the
+ * ExtIV filled in for CCMP and this also adjusts
+ * the headers which simplifies our work below.
+ */
+ k = ieee80211_crypto_encap(ic, ni, m0);
+ if (k == NULL) {
+ /*
+ * This can happen when the key is yanked after the
+ * frame was queued. Just discard the frame; the
+ * 802.11 layer counts failures and provides
+ * debugging/diagnostics.
+ */
+ m_freem(m0);
+ return EIO;
+ }
+
+ /*
+ * Adjust the packet length for the crypto additions
+ * done during encap and any other bits that the f/w
+ * will add later on.
+ */
+ pktlen = m0->m_pkthdr.len;
+
+ /* packet header may have moved, reset our local pointer */
+ wh = mtod(m0, struct ieee80211_frame *);
+ }
+
+ if (bpf_peers_present(sc->malo_drvbpf)) {
+ sc->malo_tx_th.wt_flags = 0; /* XXX */
+ if (iswep)
+ sc->malo_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_WEP;
+ sc->malo_tx_th.wt_txpower = ni->ni_txpower;
+ sc->malo_tx_th.wt_antenna = sc->malo_txantenna;
+
+ bpf_mtap2(sc->malo_drvbpf,
+ &sc->malo_tx_th, sc->malo_tx_th_len, m0);
+ }
+
+ /*
+ * Copy up/down the 802.11 header; the firmware requires
+ * we present a 2-byte payload length followed by a
+ * 4-address header (w/o QoS), followed (optionally) by
+ * any WEP/ExtIV header (but only filled in for CCMP).
+ * We are assured the mbuf has sufficient headroom to
+ * prepend in-place by the setup of ic_headroom in
+ * malo_attach.
+ */
+ if (hdrlen < sizeof(struct malo_txrec)) {
+ const int space = sizeof(struct malo_txrec) - hdrlen;
+ if (M_LEADINGSPACE(m0) < space) {
+ /* NB: should never happen */
+ device_printf(sc->malo_dev,
+ "not enough headroom, need %d found %zd, "
+ "m_flags 0x%x m_len %d\n",
+ space, M_LEADINGSPACE(m0), m0->m_flags, m0->m_len);
+ ieee80211_dump_pkt(ic,
+ mtod(m0, const uint8_t *), m0->m_len, 0, -1);
+ m_freem(m0);
+ /* XXX stat */
+ return EIO;
+ }
+ M_PREPEND(m0, space, M_NOWAIT);
+ }
+ tr = mtod(m0, struct malo_txrec *);
+ if (wh != (struct ieee80211_frame *) &tr->wh)
+ ovbcopy(wh, &tr->wh, hdrlen);
+ /*
+ * Note: the "firmware length" is actually the length of the fully
+ * formed "802.11 payload". That is, it's everything except for
+ * the 802.11 header. In particular this includes all crypto
+ * material including the MIC!
+ */
+ tr->fwlen = htole16(pktlen - hdrlen);
+
+ /*
+ * Load the DMA map so any coalescing is done. This
+ * also calculates the number of descriptors we need.
+ */
+ error = malo_tx_dmasetup(sc, bf, m0);
+ if (error != 0)
+ return error;
+ bf->bf_node = ni; /* NB: held reference */
+ m0 = bf->bf_m; /* NB: may have changed */
+ tr = mtod(m0, struct malo_txrec *);
+ wh = (struct ieee80211_frame *)&tr->wh;
+
+ /*
+ * Formulate tx descriptor.
+ */
+ ds = bf->bf_desc;
+ txq = bf->bf_txq;
+
+ ds->qosctrl = qos; /* NB: already little-endian */
+ ds->pktptr = htole32(bf->bf_segs[0].ds_addr);
+ ds->pktlen = htole16(bf->bf_segs[0].ds_len);
+ /* NB: pPhysNext setup once, don't touch */
+ ds->datarate = IS_DATA_FRAME(wh) ? 1 : 0;
+ ds->sap_pktinfo = 0;
+ ds->format = 0;
+
+ /*
+ * Select transmit rate.
+ */
+ switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) {
+ case IEEE80211_FC0_TYPE_MGT:
+ sc->malo_stats.mst_tx_mgmt++;
+ /* fall thru... */
+ case IEEE80211_FC0_TYPE_CTL:
+ ds->txpriority = 1;
+ break;
+ case IEEE80211_FC0_TYPE_DATA:
+ ds->txpriority = txq->qnum;
+ break;
+ default:
+ if_printf(ifp, "bogus frame type 0x%x (%s)\n",
+ wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK, __func__);
+ /* XXX statistic */
+ m_freem(m0);
+ return EIO;
+ }
+
+#ifdef MALO_DEBUG
+ if (IFF_DUMPPKTS_XMIT(sc))
+ ieee80211_dump_pkt(ic,
+ mtod(m0, const uint8_t *)+sizeof(uint16_t),
+ m0->m_len - sizeof(uint16_t), ds->datarate, -1);
+#endif
+
+ MALO_TXQ_LOCK(txq);
+ if (!IS_DATA_FRAME(wh))
+ ds->status |= htole32(1);
+ ds->status |= htole32(MALO_TXD_STATUS_FW_OWNED);
+ STAILQ_INSERT_TAIL(&txq->active, bf, bf_list);
+ MALO_TXDESC_SYNC(txq, ds, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+ ifp->if_opackets++;
+ ifp->if_timer = 5;
+ MALO_TXQ_UNLOCK(txq);
+ return 0;
+#undef IEEE80211_DIR_DSTODS
+}
+
+static void
+malo_start(struct ifnet *ifp)
+{
+ int nqueued = 0;
+ struct ether_header *eh;
+ struct malo_softc *sc = ifp->if_softc;
+ struct ieee80211_frame *wh;
+ struct ieee80211_node *ni;
+ struct ieee80211com *ic = &sc->malo_ic;
+ struct malo_txbuf *bf = NULL;
+ struct malo_txq *txq = NULL;
+ struct mbuf *m;
+
+ if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || sc->malo_invalid)
+ return;
+
+ for (;;) {
+ /*
+ * Poll the management queue for frames; they
+ * have priority over normal data frames.
+ */
+ IF_DEQUEUE(&ic->ic_mgtq, m);
+ if (m == NULL) {
+ /*
+ * No data frames go out unless we're associated.
+ */
+ if (ic->ic_state != IEEE80211_S_RUN) {
+ DPRINTF(sc, MALO_DEBUG_XMIT,
+ "%s: discard data packet, state %s\n",
+ __func__,
+ ieee80211_state_name[ic->ic_state]);
+ sc->malo_stats.mst_tx_discard++;
+ break;
+ }
+ IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
+ if (m == NULL)
+ break;
+ /*
+ * Cancel any background scan.
+ */
+ if (ic->ic_flags & IEEE80211_F_SCAN)
+ ieee80211_cancel_scan(ic);
+
+ /*
+ * Find the node for the destination so we can do
+ * things like power save and fast frames aggregation.
+ */
+ if (m->m_len < sizeof(struct ether_header) &&
+ (m = m_pullup(m, sizeof(struct ether_header))) ==
+ NULL) {
+ ic->ic_stats.is_tx_nobuf++; /* XXX */
+ ni = NULL;
+ goto bad;
+ }
+ eh = mtod(m, struct ether_header *);
+ ni = ieee80211_find_txnode(ic, eh->ether_dhost);
+ if (ni == NULL) {
+ /* NB: ieee80211_find_txnode does stat+msg */
+ m_freem(m);
+ goto bad;
+ }
+ /* calculate priority so we can find the tx queue */
+ if (ieee80211_classify(ic, m, ni)) {
+ DPRINTF(sc, MALO_DEBUG_XMIT,
+ "%s: discard, classification failure\n",
+ __func__);
+ m_freem(m);
+ goto bad;
+ }
+
+ txq = &sc->malo_txq[0];
+
+ bf = malo_getbuf(sc, txq);
+ if (bf == NULL) {
+ IFQ_DRV_PREPEND(&ifp->if_snd, m);
+ ieee80211_free_node(ni);
+
+ /* XXX blocks other traffic */
+ ifp->if_drv_flags |= IFF_DRV_OACTIVE;
+ sc->malo_stats.mst_tx_qstop++;
+ break;
+ }
+ ifp->if_opackets++;
+
+ if (bpf_peers_present(ifp->if_bpf))
+ bpf_mtap(ifp->if_bpf, m);
+
+ /*
+ * Encapsulate the packet in prep for transmission.
+ */
+ m = ieee80211_encap(ic, m, ni);
+ if (m == NULL) {
+ DPRINTF(sc, MALO_DEBUG_XMIT,
+ "%s: encapsulation failure\n", __func__);
+ sc->malo_stats.mst_tx_encap++;
+ goto bad;
+ }
+ } else {
+ /*
+ * Grab a TX buffer and associated resources.
+ * Note that we depend on the classification
+ * by the 802.11 layer to get to the right h/w
+ * queue. Management frames must ALWAYS go on
+ * queue 1 but we cannot just force that here
+ * because we may receive non-mgt frames through
+ * the ic_mgtq (e.g. null data frames).
+ */
+ txq = &sc->malo_txq[0];
+ bf = malo_getbuf(sc, txq);
+ if (bf == NULL) {
+ IF_PREPEND(&ic->ic_mgtq, m);
+ /* XXX stat */
+ break;
+ }
+
+ /*
+ * Hack! The referenced node pointer is in the
+ * rcvif field of the packet header. This is
+ * placed there by ieee80211_mgmt_output because
+ * we need to hold the reference with the frame
+ * and there's no other way (other than packet
+ * tags which we consider too expensive to use)
+ * to pass it along.
+ */
+ ni = (struct ieee80211_node *) m->m_pkthdr.rcvif;
+ m->m_pkthdr.rcvif = NULL;
+
+ wh = mtod(m, struct ieee80211_frame *);
+ sc->malo_stats.mst_tx_mgmt++;
+
+ if (bpf_peers_present(ic->ic_rawbpf))
+ bpf_mtap(ic->ic_rawbpf, m);
+ }
+
+ /*
+ * Pass the frame to the h/w for transmission.
+ */
+ if (malo_tx_start(sc, ni, bf, m)) {
+ bad:
+ ifp->if_oerrors++;
+ if (bf != NULL) {
+ bf->bf_m = NULL;
+ bf->bf_node = NULL;
+ MALO_TXQ_LOCK(txq);
+ STAILQ_INSERT_HEAD(&txq->free, bf, bf_list);
+ MALO_TXQ_UNLOCK(txq);
+ }
+ ieee80211_free_node(ni);
+ continue;
+ }
+ nqueued++;
+
+ if (nqueued >= malo_txcoalesce) {
+ /*
+ * Poke the firmware to process queued frames;
+ * see below about (lack of) locking.
+ */
+ nqueued = 0;
+ malo_hal_txstart(sc->malo_mh, 0/*XXX*/);
+ }
+ }
+
+ if (nqueued) {
+ /*
+ * NB: We don't need to lock against tx done because
+ * this just prods the firmware to check the transmit
+ * descriptors. The firmware will also start fetching
+ * descriptors by itself if it notices new ones are
+ * present when it goes to deliver a tx done interrupt
+ * to the host. So if we race with tx done processing
+ * it's ok. Delivering the kick here rather than in
+ * malo_tx_start is an optimization to avoid poking the
+ * firmware for each packet.
+ *
+ * NB: the queue id isn't used so 0 is ok.
+ */
+ malo_hal_txstart(sc->malo_mh, 0/*XXX*/);
+ }
+}
+
+static void
+malo_watchdog(struct ifnet *ifp)
+{
+ struct malo_softc *sc = ifp->if_softc;
+
+ if ((ifp->if_drv_flags & IFF_DRV_RUNNING) && !sc->malo_invalid) {
+ if_printf(ifp, "watchdog timeout\n");
+
+ /* XXX no way to reset h/w. now */
+
+ ifp->if_oerrors++;
+ sc->malo_stats.mst_watchdog++;
+ }
+}
+
+static int
+malo_hal_reset(struct malo_softc *sc)
+{
+ static int first = 0;
+ struct ieee80211com *ic = &sc->malo_ic;
+ struct malo_hal *mh = sc->malo_mh;
+
+ if (first == 0) {
+ /*
+ * NB: when the device firstly is initialized, sometimes
+ * firmware could override rx/tx dma registers so we re-set
+ * these values once.
+ */
+ malo_hal_set_rxtxdma(sc);
+ first = 1;
+ }
+
+ malo_hal_setantenna(mh, MHA_ANTENNATYPE_RX, sc->malo_rxantenna);
+ malo_hal_setantenna(mh, MHA_ANTENNATYPE_TX, sc->malo_txantenna);
+ malo_hal_setradio(mh, 1, MHP_AUTO_PREAMBLE);
+ malo_chan_set(sc, ic->ic_curchan);
+
+ /* XXX needs other stuffs? */
+
+ return 1;
+}
+
+static __inline struct mbuf *
+malo_getrxmbuf(struct malo_softc *sc, struct malo_rxbuf *bf)
+{
+ struct mbuf *m;
+ bus_addr_t paddr;
+ int error;
+
+ /* XXX don't need mbuf, just dma buffer */
+ m = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR, MJUMPAGESIZE);
+ if (m == NULL) {
+ sc->malo_stats.mst_rx_nombuf++; /* XXX */
+ return NULL;
+ }
+ error = bus_dmamap_load(sc->malo_dmat, bf->bf_dmamap,
+ mtod(m, caddr_t), MJUMPAGESIZE,
+ malo_load_cb, &paddr, BUS_DMA_NOWAIT);
+ if (error != 0) {
+ if_printf(sc->malo_ifp,
+ "%s: bus_dmamap_load failed, error %d\n", __func__, error);
+ m_freem(m);
+ return NULL;
+ }
+ bf->bf_data = paddr;
+ bus_dmamap_sync(sc->malo_dmat, bf->bf_dmamap, BUS_DMASYNC_PREWRITE);
+
+ return m;
+}
+
+static int
+malo_rxbuf_init(struct malo_softc *sc, struct malo_rxbuf *bf)
+{
+ struct malo_rxdesc *ds;
+
+ ds = bf->bf_desc;
+ if (bf->bf_m == NULL) {
+ bf->bf_m = malo_getrxmbuf(sc, bf);
+ if (bf->bf_m == NULL) {
+ /* mark descriptor to be skipped */
+ ds->rxcontrol = MALO_RXD_CTRL_OS_OWN;
+ /* NB: don't need PREREAD */
+ MALO_RXDESC_SYNC(sc, ds, BUS_DMASYNC_PREWRITE);
+ return ENOMEM;
+ }
+ }
+
+ /*
+ * Setup descriptor.
+ */
+ ds->qosctrl = 0;
+ ds->snr = 0;
+ ds->status = MALO_RXD_STATUS_IDLE;
+ ds->channel = 0;
+ ds->pktlen = htole16(MALO_RXSIZE);
+ ds->nf = 0;
+ ds->physbuffdata = htole32(bf->bf_data);
+ /* NB: don't touch pPhysNext, set once */
+ ds->rxcontrol = MALO_RXD_CTRL_DRIVER_OWN;
+ MALO_RXDESC_SYNC(sc, ds, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+ return 0;
+}
+
+/*
+ * Setup the rx data structures. This should only be done once or we may get
+ * out of sync with the firmware.
+ */
+static int
+malo_startrecv(struct malo_softc *sc)
+{
+ struct malo_rxbuf *bf, *prev;
+ struct malo_rxdesc *ds;
+
+ if (sc->malo_recvsetup == 1) {
+ malo_mode_init(sc); /* set filters, etc. */
+ return 0;
+ }
+
+ prev = NULL;
+ STAILQ_FOREACH(bf, &sc->malo_rxbuf, bf_list) {
+ int error = malo_rxbuf_init(sc, bf);
+ if (error != 0) {
+ DPRINTF(sc, MALO_DEBUG_RECV,
+ "%s: malo_rxbuf_init failed %d\n",
+ __func__, error);
+ return error;
+ }
+ if (prev != NULL) {
+ ds = prev->bf_desc;
+ ds->physnext = htole32(bf->bf_daddr);
+ }
+ prev = bf;
+ }
+ if (prev != NULL) {
+ ds = prev->bf_desc;
+ ds->physnext =
+ htole32(STAILQ_FIRST(&sc->malo_rxbuf)->bf_daddr);
+ }
+
+ sc->malo_recvsetup = 1;
+
+ malo_mode_init(sc); /* set filters, etc. */
+
+ return 0;
+}
+
+static void
+malo_init(void *arg)
+{
+ struct malo_softc *sc = (struct malo_softc *) arg;
+ struct ieee80211com *ic = &sc->malo_ic;
+ struct ifnet *ifp = sc->malo_ifp;
+ struct malo_hal *mh = sc->malo_mh;
+ int error;
+
+ DPRINTF(sc, MALO_DEBUG_ANY, "%s: if_flags 0x%x\n",
+ __func__, ifp->if_flags);
+
+ if (!sc->malo_fw_loaded) {
+ /*
+ * Load firmware so we can get setup.
+ */
+ error = malo_hal_fwload(mh, "malo8335-h", "malo8335-m");
+ if (error != 0) {
+ if_printf(ifp, "unable to setup firmware\n");
+ return;
+ }
+ /* XXX gethwspecs() extracts correct informations? not maybe! */
+ error = malo_hal_gethwspecs(mh, &sc->malo_hwspecs);
+ if (error != 0) {
+ if_printf(ifp, "unable to fetch h/w specs\n");
+ return;
+ }
+
+ DPRINTF(sc, MALO_DEBUG_FW,
+ "malo_hal_gethwspecs: hwversion 0x%x hostif 0x%x"
+ "maxnum_wcb 0x%x maxnum_mcaddr 0x%x maxnum_tx_wcb 0x%x"
+ "regioncode 0x%x num_antenna 0x%x fw_releasenum 0x%x"
+ "wcbbase0 0x%x rxdesc_read 0x%x rxdesc_write 0x%x"
+ "ul_fw_awakecookie 0x%x w[4] = %x %x %x %x",
+ sc->malo_hwspecs.hwversion,
+ sc->malo_hwspecs.hostinterface, sc->malo_hwspecs.maxnum_wcb,
+ sc->malo_hwspecs.maxnum_mcaddr,
+ sc->malo_hwspecs.maxnum_tx_wcb,
+ sc->malo_hwspecs.regioncode, sc->malo_hwspecs.num_antenna,
+ sc->malo_hwspecs.fw_releasenum, sc->malo_hwspecs.wcbbase0,
+ sc->malo_hwspecs.rxdesc_read, sc->malo_hwspecs.rxdesc_write,
+ sc->malo_hwspecs.ul_fw_awakecookie,
+ sc->malo_hwspecs.wcbbase[0], sc->malo_hwspecs.wcbbase[1],
+ sc->malo_hwspecs.wcbbase[2], sc->malo_hwspecs.wcbbase[3]);
+
+ error = malo_setup_hwdma(sc); /* push to firmware */
+ /* NB: malo_setupdma prints msg */
+ if (error != 0) {
+ if_printf(ifp, "%s: failed to set up h/w dma\n",
+ __func__);
+ return;
+ }
+
+ /* set reddomain. */
+ ic->ic_regdomain = sc->malo_hwspecs.regioncode;
+
+ malo_announce(sc);
+
+ sc->malo_fw_loaded = 1;
+ }
+
+ MALO_LOCK(sc);
+
+ /*
+ * Stop anything previously setup. This is safe whether this is
+ * the first time through or not.
+ */
+ malo_stop_locked(ifp, 0);
+
+ /*
+ * Push state to the firmware.
+ */
+ if (!malo_hal_reset(sc)) {
+ if_printf(ifp, "%s: unable to reset hardware\n", __func__);
+ goto done;
+ }
+
+ /*
+ * Setup recv (once); transmit is already good to go.
+ */
+ error = malo_startrecv(sc);
+ if (error != 0) {
+ if_printf(ifp, "%s: unable to start recv logic, error %d\n",
+ __func__, error);
+ goto done;
+ }
+
+ /*
+ * Enable interrupts.
+ */
+ sc->malo_imask = MALO_A2HRIC_BIT_RX_RDY
+ | MALO_A2HRIC_BIT_TX_DONE
+ | MALO_A2HRIC_BIT_OPC_DONE
+ | MALO_A2HRIC_BIT_MAC_EVENT
+ | MALO_A2HRIC_BIT_RX_PROBLEM
+ | MALO_A2HRIC_BIT_ICV_ERROR
+ | MALO_A2HRIC_BIT_RADAR_DETECT
+ | MALO_A2HRIC_BIT_CHAN_SWITCH;
+
+ ifp->if_drv_flags |= IFF_DRV_RUNNING;
+ ic->ic_state = IEEE80211_S_INIT;
+ IEEE80211_ADDR_COPY(ic->ic_myaddr, IF_LLADDR(ifp));
+
+ malo_hal_intrset(mh, sc->malo_imask);
+
+ /*
+ * The hardware should be ready to go now so it's safe to kick
+ * the 802.11 state machine as it's likely to immediately call back
+ * to us to send mgmt frames.
+ */
+ if (ic->ic_opmode != IEEE80211_M_MONITOR) {
+ if (ic->ic_roaming != IEEE80211_ROAMING_MANUAL)
+ ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
+ } else
+ ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
+
+done:
+ if (error != 0)
+ if_printf(ifp,
+ "error(%d) occurred during the initializing.\n", error);
+
+ MALO_UNLOCK(sc);
+
+ return;
+}
+
+/*
+ * Set the multicast filter contents into the hardware.
+ */
+static void
+malo_setmcastfilter(struct malo_softc *sc)
+{
+ struct ieee80211com *ic = &sc->malo_ic;
+ struct ifmultiaddr *ifma;
+ struct ifnet *ifp = sc->malo_ifp;
+ uint8_t macs[IEEE80211_ADDR_LEN * MALO_HAL_MCAST_MAX];
+ uint8_t *mp;
+ int nmc;
+
+ mp = macs;
+ nmc = 0;
+
+ if (ic->ic_opmode == IEEE80211_M_MONITOR ||
+ (ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)))
+ goto all;
+
+ IF_ADDR_LOCK(ifp);
+ TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+ if (ifma->ifma_addr->sa_family != AF_LINK)
+ continue;
+
+ if (nmc == MALO_HAL_MCAST_MAX) {
+ ifp->if_flags |= IFF_ALLMULTI;
+ IF_ADDR_UNLOCK(ifp);
+ goto all;
+ }
+ IEEE80211_ADDR_COPY(mp,
+ LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
+
+ mp += IEEE80211_ADDR_LEN, nmc++;
+ }
+ IF_ADDR_UNLOCK(ifp);
+
+ malo_hal_setmcast(sc->malo_mh, nmc, macs);
+
+all:
+ /*
+ * XXX we don't know how to set the f/w for supporting
+ * IFF_ALLMULTI | IFF_PROMISC cases
+ */
+ return;
+}
+
+static int
+malo_mode_init(struct malo_softc *sc)
+{
+ struct ieee80211com *ic = &sc->malo_ic;
+ struct ifnet *ifp = ic->ic_ifp;
+ struct malo_hal *mh = sc->malo_mh;
+
+ /*
+ * Handle any link-level address change. Note that we only
+ * need to force ic_myaddr; any other addresses are handled
+ * as a byproduct of the ifnet code marking the interface
+ * down then up.
+ */
+ IEEE80211_ADDR_COPY(ic->ic_myaddr, IF_LLADDR(ifp));
+
+ /*
+ * NB: Ignore promisc in hostap mode; it's set by the
+ * bridge. This is wrong but we have no way to
+ * identify internal requests (from the bridge)
+ * versus external requests such as for tcpdump.
+ */
+ malo_hal_setpromisc(mh, (ifp->if_flags & IFF_PROMISC) &&
+ ic->ic_opmode != IEEE80211_M_HOSTAP);
+ malo_setmcastfilter(sc);
+
+ return ENXIO;
+}
+
+static void
+malo_tx_draintxq(struct malo_softc *sc, struct malo_txq *txq)
+{
+ struct ieee80211_node *ni;
+ struct malo_txbuf *bf;
+ u_int ix;
+
+ /*
+ * NB: this assumes output has been stopped and
+ * we do not need to block malo_tx_tasklet
+ */
+ for (ix = 0;; ix++) {
+ MALO_TXQ_LOCK(txq);
+ bf = STAILQ_FIRST(&txq->active);
+ if (bf == NULL) {
+ MALO_TXQ_UNLOCK(txq);
+ break;
+ }
+ STAILQ_REMOVE_HEAD(&txq->active, bf_list);
+ MALO_TXQ_UNLOCK(txq);
+#ifdef MALO_DEBUG
+ if (sc->malo_debug & MALO_DEBUG_RESET) {
+ const struct malo_txrec *tr =
+ mtod(bf->bf_m, const struct malo_txrec *);
+ malo_printtxbuf(bf, txq->qnum, ix);
+ ieee80211_dump_pkt(&sc->malo_ic,
+ (const uint8_t *)&tr->wh,
+ bf->bf_m->m_len - sizeof(tr->fwlen), 0, -1);
+ }
+#endif /* MALO_DEBUG */
+ bus_dmamap_unload(sc->malo_dmat, bf->bf_dmamap);
+ ni = bf->bf_node;
+ bf->bf_node = NULL;
+ if (ni != NULL) {
+ /*
+ * Reclaim node reference.
+ */
+ ieee80211_free_node(ni);
+ }
+ m_freem(bf->bf_m);
+ bf->bf_m = NULL;
+
+ MALO_TXQ_LOCK(txq);
+ STAILQ_INSERT_TAIL(&txq->free, bf, bf_list);
+ txq->nfree++;
+ MALO_TXQ_UNLOCK(txq);
+ }
+}
+
+static void
+malo_stop_locked(struct ifnet *ifp, int disable)
+{
+ int i;
+ struct malo_softc *sc = ifp->if_softc;
+ struct ieee80211com *ic = &sc->malo_ic;
+ struct malo_hal *mh = sc->malo_mh;
+
+ DPRINTF(sc, MALO_DEBUG_ANY, "%s: invalid %u if_flags 0x%x\n",
+ __func__, sc->malo_invalid, ifp->if_flags);
+
+ MALO_LOCK_ASSERT(sc);
+
+ if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
+ return;
+
+ /*
+ * Shutdown the hardware and driver:
+ * reset 802.11 state machine
+ * turn off timers
+ * disable interrupts
+ * turn off the radio
+ * clear transmit machinery
+ * clear receive machinery
+ * drain and release tx queues
+ * reclaim beacon resources
+ * power down hardware
+ *
+ * Note that some of this work is not possible if the hardware
+ * is gone (invalid).
+ */
+ ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
+ ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
+ ifp->if_timer = 0;
+ if (sc->malo_fw_loaded == 1) {
+ /* diable interrupt. */
+ malo_hal_intrset(mh, 0);
+ /* turn off the radio. */
+ malo_hal_setradio(mh, 0, MHP_AUTO_PREAMBLE);
+ }
+
+ /* drain and release tx queues. */
+ for (i = 0; i < MALO_NUM_TX_QUEUES; i++)
+ malo_tx_draintxq(sc, &sc->malo_txq[i]);
+}
+
+static int
+malo_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
+{
+#define MALO_IS_RUNNING(ifp) \
+ ((ifp->if_flags & IFF_UP) && (ifp->if_drv_flags & IFF_DRV_RUNNING))
+ struct malo_softc *sc = ifp->if_softc;
+ struct ieee80211com *ic = &sc->malo_ic;
+ int error = 0;
+
+ MALO_LOCK(sc);
+
+ switch (cmd) {
+ case SIOCSIFFLAGS:
+ if (MALO_IS_RUNNING(ifp)) {
+ /*
+ * To avoid rescanning another access point,
+ * do not call malo_init() here. Instead,
+ * only reflect promisc mode settings.
+ */
+ malo_mode_init(sc);
+ } else if (ifp->if_flags & IFF_UP) {
+ /*
+ * Beware of being called during attach/detach
+ * to reset promiscuous mode. In that case we
+ * will still be marked UP but not RUNNING.
+ * However trying to re-init the interface
+ * is the wrong thing to do as we've already
+ * torn down much of our state. There's
+ * probably a better way to deal with this.
+ */
+ if (!sc->malo_invalid)
+ malo_init(sc);
+ } else
+ malo_stop_locked(ifp, 1);
+ break;
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ /*
+ * The upper layer has already installed/removed
+ * the multicast address(es), just recalculate the
+ * multicast filter for the card.
+ */
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING)
+ malo_mode_init(sc);
+ break;
+ default:
+ error = ieee80211_ioctl(ic, cmd, data);
+ if (error == ENETRESET) {
+ if (MALO_IS_RUNNING(ifp) &&
+ ic->ic_roaming != IEEE80211_ROAMING_MANUAL)
+ malo_init(sc);
+ error = 0;
+ }
+ if (error == ERESTART) {
+ /* XXX we need to reset the device here. */
+ error = 0;
+ }
+ break;
+ }
+
+ MALO_UNLOCK(sc);
+
+ return error;
+#undef MALO_IS_RUNNING
+}
+
+/*
+ * Callback from the 802.11 layer to update the slot time
+ * based on the current setting. We use it to notify the
+ * firmware of ERP changes and the f/w takes care of things
+ * like slot time and preamble.
+ */
+static void
+malo_updateslot(struct ifnet *ifp)
+{
+ struct malo_softc *sc = ifp->if_softc;
+ struct ieee80211com *ic = &sc->malo_ic;
+ struct malo_hal *mh = sc->malo_mh;
+ int error;
+
+ /* NB: can be called early; suppress needless cmds */
+ if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
+ return;
+
+ DPRINTF(sc, MALO_DEBUG_RESET,
+ "%s: chan %u MHz/flags 0x%x %s slot, (ic_flags 0x%x)\n",
+ __func__, ic->ic_curchan->ic_freq, ic->ic_curchan->ic_flags,
+ ic->ic_flags & IEEE80211_F_SHSLOT ? "short" : "long", ic->ic_flags);
+
+ if (ic->ic_flags & IEEE80211_F_SHSLOT)
+ error = malo_hal_set_slot(mh, 1);
+ else
+ error = malo_hal_set_slot(mh, 0);
+
+ if (error != 0)
+ device_printf(sc->malo_dev, "setting %s slot failed\n",
+ ic->ic_flags & IEEE80211_F_SHSLOT ? "short" : "long");
+}
+
+static int
+malo_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
+{
+ struct ieee80211_node *ni = ic->ic_bss;
+ struct ifnet *ifp = ic->ic_ifp;
+ struct malo_softc *sc = ifp->if_softc;
+ struct malo_hal *mh = sc->malo_mh;
+ int error;
+
+ DPRINTF(sc, MALO_DEBUG_STATE, "%s: %s -> %s\n", __func__,
+ ieee80211_state_name[ic->ic_state],
+ ieee80211_state_name[nstate]);
+
+ /*
+ * Carry out firmware actions per-state.
+ */
+ switch (nstate) {
+ case IEEE80211_S_INIT:
+ case IEEE80211_S_SCAN:
+ case IEEE80211_S_AUTH:
+ /* NB: do nothing. */
+ break;
+ case IEEE80211_S_ASSOC:
+ malo_hal_setradio(mh, 1,
+ (ic->ic_flags & IEEE80211_F_SHPREAMBLE) ?
+ MHP_SHORT_PREAMBLE : MHP_LONG_PREAMBLE);
+ break;
+ case IEEE80211_S_RUN:
+ DPRINTF(sc, MALO_DEBUG_STATE,
+ "%s: %s(RUN): ic_flags 0x%08x bintvl %d bssid %s "
+ "capinfo 0x%04x chan %d\n",
+ ifp->if_xname, __func__, ic->ic_flags,
+ ni->ni_intval, ether_sprintf(ni->ni_bssid), ni->ni_capinfo,
+ ieee80211_chan2ieee(ic, ic->ic_curchan));
+
+ switch (ic->ic_opmode) {
+ case IEEE80211_M_STA:
+ DPRINTF(sc, MALO_DEBUG_STATE, "%s: %s: aid 0x%x\n",
+ ic->ic_ifp->if_xname, __func__, ni->ni_associd);
+ malo_hal_setassocid(sc->malo_mh,
+ ni->ni_bssid, ni->ni_associd);
+
+ if (ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE)
+ /* automatic rate adaption */
+ malo_hal_set_rate(mh, ic->ic_curmode, 0);
+ else
+ /* fixed rate */
+ malo_hal_set_rate(mh, ic->ic_curmode,
+ malo_fix2rate(ic->ic_fixed_rate));
+ break;
+ default:
+ break;
+ }
+
+ break;
+ default:
+ if_printf(ifp, "%s: can't handle state %s -> %s\n",
+ __func__, ieee80211_state_name[ic->ic_state],
+ ieee80211_state_name[nstate]);
+ }
+
+ /*
+ * Invoke the parent method to complete the work.
+ */
+ error = sc->malo_newstate(ic, nstate, arg);
+
+ return error;
+}
+
+static int
+malo_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
+ const struct ieee80211_bpf_params *params)
+{
+ struct ieee80211com *ic = ni->ni_ic;
+ struct ifnet *ifp = ic->ic_ifp;
+ struct malo_softc *sc = ifp->if_softc;
+ struct malo_txbuf *bf;
+ struct malo_txq *txq;
+
+ if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || sc->malo_invalid) {
+ ieee80211_free_node(ni);
+ m_freem(m);
+ return ENETDOWN;
+ }
+
+ /*
+ * Grab a TX buffer and associated resources. Note that we depend
+ * on the classification by the 802.11 layer to get to the right h/w
+ * queue. Management frames must ALWAYS go on queue 1 but we
+ * cannot just force that here because we may receive non-mgt frames.
+ */
+ txq = &sc->malo_txq[0];
+ bf = malo_getbuf(sc, txq);
+ if (bf == NULL) {
+ /* XXX blocks other traffic */
+ ifp->if_drv_flags |= IFF_DRV_OACTIVE;
+ ieee80211_free_node(ni);
+ m_freem(m);
+ return ENOBUFS;
+ }
+
+ /*
+ * Pass the frame to the h/w for transmission.
+ */
+ if (malo_tx_start(sc, ni, bf, m) != 0) {
+ ifp->if_oerrors++;
+ bf->bf_m = NULL;
+ bf->bf_node = NULL;
+ MALO_TXQ_LOCK(txq);
+ STAILQ_INSERT_HEAD(&txq->free, bf, bf_list);
+ txq->nfree++;
+ MALO_TXQ_UNLOCK(txq);
+
+ ieee80211_free_node(ni);
+ return EIO; /* XXX */
+ }
+
+ /*
+ * NB: We don't need to lock against tx done because this just
+ * prods the firmware to check the transmit descriptors. The firmware
+ * will also start fetching descriptors by itself if it notices
+ * new ones are present when it goes to deliver a tx done interrupt
+ * to the host. So if we race with tx done processing it's ok.
+ * Delivering the kick here rather than in malo_tx_start is
+ * an optimization to avoid poking the firmware for each packet.
+ *
+ * NB: the queue id isn't used so 0 is ok.
+ */
+ malo_hal_txstart(sc->malo_mh, 0/*XXX*/);
+
+ return 0;
+}
+
+static int
+malo_media_change(struct ifnet *ifp)
+{
+#define IS_UP(ifp) \
+ ((ifp->if_flags & IFF_UP) && (ifp->if_drv_flags & IFF_DRV_RUNNING))
+ int error;
+
+ error = ieee80211_media_change(ifp);
+ if (error == ENETRESET) {
+ struct malo_softc *sc = ifp->if_softc;
+
+ if (IS_UP(ifp))
+ malo_init(sc);
+ error = 0;
+ }
+ return error;
+#undef IS_UP
+}
+
+static void
+malo_bpfattach(struct malo_softc *sc)
+{
+ struct ifnet *ifp = sc->malo_ifp;
+
+ bpfattach2(ifp, DLT_IEEE802_11_RADIO,
+ sizeof(struct ieee80211_frame) + sizeof(sc->malo_tx_th),
+ &sc->malo_drvbpf);
+
+ /*
+ * Initialize constant fields.
+ * XXX make header lengths a multiple of 32-bits so subsequent
+ * headers are properly aligned; this is a kludge to keep
+ * certain applications happy.
+ *
+ * NB: the channel is setup each time we transition to the
+ * RUN state to avoid filling it in for each frame.
+ */
+ sc->malo_tx_th_len = roundup(sizeof(sc->malo_tx_th), sizeof(uint32_t));
+ sc->malo_tx_th.wt_ihdr.it_len = htole16(sc->malo_tx_th_len);
+ sc->malo_tx_th.wt_ihdr.it_present = htole32(MALO_TX_RADIOTAP_PRESENT);
+
+ sc->malo_rx_th_len = roundup(sizeof(sc->malo_rx_th), sizeof(uint32_t));
+ sc->malo_rx_th.wr_ihdr.it_len = htole16(sc->malo_rx_th_len);
+ sc->malo_rx_th.wr_ihdr.it_present = htole32(MALO_RX_RADIOTAP_PRESENT);
+}
+
+static void
+malo_sysctlattach(struct malo_softc *sc)
+{
+#ifdef MALO_DEBUG
+ struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->malo_dev);
+ struct sysctl_oid *tree = device_get_sysctl_tree(sc->malo_dev);
+
+ sc->malo_debug = malo_debug;
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "debug", CTLFLAG_RW, &sc->malo_debug, 0,
+ "control debugging printfs");
+#endif
+}
+
+static void
+malo_announce(struct malo_softc *sc)
+{
+ struct ifnet *ifp = sc->malo_ifp;
+
+ if_printf(ifp, "versions [hw %d fw %d.%d.%d.%d] (regioncode %d)\n",
+ sc->malo_hwspecs.hwversion,
+ (sc->malo_hwspecs.fw_releasenum >> 24) & 0xff,
+ (sc->malo_hwspecs.fw_releasenum >> 16) & 0xff,
+ (sc->malo_hwspecs.fw_releasenum >> 8) & 0xff,
+ (sc->malo_hwspecs.fw_releasenum >> 0) & 0xff,
+ sc->malo_hwspecs.regioncode);
+
+ if (bootverbose || malo_rxbuf != MALO_RXBUF)
+ if_printf(ifp, "using %u rx buffers\n", malo_rxbuf);
+ if (bootverbose || malo_txbuf != MALO_TXBUF)
+ if_printf(ifp, "using %u tx buffers\n", malo_txbuf);
+}
+
+/*
+ * Convert net80211 channel to a HAL channel.
+ */
+static void
+malo_mapchan(struct malo_hal_channel *hc, const struct ieee80211_channel *chan)
+{
+ hc->channel = chan->ic_ieee;
+
+ *(uint32_t *)&hc->flags = 0;
+ if (IEEE80211_IS_CHAN_2GHZ(chan))
+ hc->flags.freqband = MALO_FREQ_BAND_2DOT4GHZ;
+}
+
+/*
+ * Set/change channels. If the channel is really being changed,
+ * it's done by reseting the chip. To accomplish this we must
+ * first cleanup any pending DMA, then restart stuff after a la
+ * malo_init.
+ */
+static int
+malo_chan_set(struct malo_softc *sc, struct ieee80211_channel *chan)
+{
+ struct malo_hal *mh = sc->malo_mh;
+ struct malo_hal_channel hchan;
+
+ DPRINTF(sc, MALO_DEBUG_RESET, "%s: chan %u MHz/flags 0x%x\n",
+ __func__, chan->ic_freq, chan->ic_flags);
+
+ /*
+ * Convert to a HAL channel description with the flags constrained
+ * to reflect the current operating mode.
+ */
+ malo_mapchan(&hchan, chan);
+ malo_hal_intrset(mh, 0); /* disable interrupts */
+ malo_hal_setchannel(mh, &hchan);
+ malo_hal_settxpower(mh, &hchan);
+
+ /*
+ * Update internal state.
+ */
+ sc->malo_tx_th.wt_chan_freq = htole16(chan->ic_freq);
+ sc->malo_rx_th.wr_chan_freq = htole16(chan->ic_freq);
+ if (IEEE80211_IS_CHAN_ANYG(chan)) {
+ sc->malo_tx_th.wt_chan_flags = htole16(IEEE80211_CHAN_G);
+ sc->malo_rx_th.wr_chan_flags = htole16(IEEE80211_CHAN_G);
+ } else {
+ sc->malo_tx_th.wt_chan_flags = htole16(IEEE80211_CHAN_B);
+ sc->malo_rx_th.wr_chan_flags = htole16(IEEE80211_CHAN_B);
+ }
+ sc->malo_curchan = hchan;
+ malo_hal_intrset(mh, sc->malo_imask);
+
+ return 0;
+}
+
+static void
+malo_scan_start(struct ieee80211com *ic)
+{
+ struct ifnet *ifp = ic->ic_ifp;
+ struct malo_softc *sc = ifp->if_softc;
+
+ DPRINTF(sc, MALO_DEBUG_STATE, "%s\n", __func__);
+}
+
+static void
+malo_scan_end(struct ieee80211com *ic)
+{
+ struct ifnet *ifp = ic->ic_ifp;
+ struct malo_softc *sc = ifp->if_softc;
+
+ DPRINTF(sc, MALO_DEBUG_STATE, "%s\n", __func__);
+}
+
+static void
+malo_set_channel(struct ieee80211com *ic)
+{
+ struct ifnet *ifp = ic->ic_ifp;
+ struct malo_softc *sc = ifp->if_softc;
+
+ (void) malo_chan_set(sc, ic->ic_curchan);
+}
+
+static void
+malo_rx_proc(void *arg, int npending)
+{
+#define IEEE80211_DIR_DSTODS(wh) \
+ ((((const struct ieee80211_frame *)wh)->i_fc[1] & \
+ IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS)
+ struct malo_softc *sc = arg;
+ struct malo_rxbuf *bf;
+ struct ieee80211com *ic = &sc->malo_ic;
+ struct ifnet *ifp = sc->malo_ifp;
+ struct malo_rxdesc *ds;
+ struct mbuf *m, *mnew;
+ struct ieee80211_qosframe *wh;
+ struct ieee80211_qosframe_addr4 *wh4;
+ struct ieee80211_node *ni;
+ int off, len, hdrlen, pktlen, rssi, ntodo;
+ uint8_t *data, status;
+ uint32_t readptr, writeptr;
+
+ DPRINTF(sc, MALO_DEBUG_RX_PROC,
+ "%s: pending %u rdptr(0x%x) 0x%x wrptr(0x%x) 0x%x\n",
+ __func__, npending,
+ sc->malo_hwspecs.rxdesc_read,
+ malo_bar0_read4(sc, sc->malo_hwspecs.rxdesc_read),
+ sc->malo_hwspecs.rxdesc_write,
+ malo_bar0_read4(sc, sc->malo_hwspecs.rxdesc_write));
+
+ readptr = malo_bar0_read4(sc, sc->malo_hwspecs.rxdesc_read);
+ writeptr = malo_bar0_read4(sc, sc->malo_hwspecs.rxdesc_write);
+ if (readptr == writeptr)
+ return;
+
+ bf = sc->malo_rxnext;
+ for (ntodo = malo_rxquota; ntodo > 0 && (readptr != writeptr);
+ ntodo--) {
+ if (bf == NULL) {
+ bf = STAILQ_FIRST(&sc->malo_rxbuf);
+ break;
+ }
+ ds = bf->bf_desc;
+ if (bf->bf_m == NULL) {
+ /*
+ * If data allocation failed previously there
+ * will be no buffer; try again to re-populate it.
+ * Note the firmware will not advance to the next
+ * descriptor with a dma buffer so we must mimic
+ * this or we'll get out of sync.
+ */
+ DPRINTF(sc, MALO_DEBUG_ANY,
+ "%s: rx buf w/o dma memory\n", __func__);
+ (void)malo_rxbuf_init(sc, bf);
+ break;
+ }
+ MALO_RXDESC_SYNC(sc, ds,
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+ if (ds->rxcontrol != MALO_RXD_CTRL_DMA_OWN)
+ break;
+
+ readptr = le32toh(ds->physnext);
+
+#ifdef MALO_DEBUG
+ if (sc->malo_debug & MALO_DEBUG_RECV_DESC)
+ malo_printrxbuf(bf, 0);
+#endif
+ status = ds->status;
+ if (status & MALO_RXD_STATUS_DECRYPT_ERR_MASK) {
+ ifp->if_ierrors++;
+ goto rx_next;
+ }
+ /*
+ * Sync the data buffer.
+ */
+ len = le16toh(ds->pktlen);
+ bus_dmamap_sync(sc->malo_dmat, bf->bf_dmamap,
+ BUS_DMASYNC_POSTREAD);
+ /*
+ * The 802.11 header is provided all or in part at the front;
+ * use it to calculate the true size of the header that we'll
+ * construct below. We use this to figure out where to copy
+ * payload prior to constructing the header.
+ */
+ m = bf->bf_m;
+ data = mtod(m, uint8_t *);
+ hdrlen = ieee80211_anyhdrsize(data + sizeof(uint16_t));
+ off = sizeof(uint16_t) + sizeof(struct ieee80211_frame_addr4);
+
+ /*
+ * Calculate RSSI. XXX wrong
+ */
+ rssi = 2 * ((int) ds->snr - ds->nf); /* NB: .5 dBm */
+ if (rssi > 100)
+ rssi = 100;
+
+ pktlen = hdrlen + (len - off);
+ /*
+ * NB: we know our frame is at least as large as
+ * IEEE80211_MIN_LEN because there is a 4-address frame at
+ * the front. Hence there's no need to vet the packet length.
+ * If the frame in fact is too small it should be discarded
+ * at the net80211 layer.
+ */
+
+ /* XXX don't need mbuf, just dma buffer */
+ mnew = malo_getrxmbuf(sc, bf);
+ if (mnew == NULL) {
+ ifp->if_ierrors++;
+ goto rx_next;
+ }
+
+ /*
+ * Attach the dma buffer to the mbuf; malo_rxbuf_init will
+ * re-setup the rx descriptor using the replacement dma
+ * buffer we just installed above.
+ */
+ bf->bf_m = mnew;
+ m->m_data += off - hdrlen;
+ m->m_pkthdr.len = m->m_len = pktlen;
+ m->m_pkthdr.rcvif = ifp;
+
+ /*
+ * Piece 802.11 header together.
+ */
+ wh = mtod(m, struct ieee80211_qosframe *);
+ /* NB: don't need to do this sometimes but ... */
+ /* XXX special case so we can memcpy after m_devget? */
+ ovbcopy(data + sizeof(uint16_t), wh, hdrlen);
+ if (IEEE80211_QOS_HAS_SEQ(wh)) {
+ if (IEEE80211_DIR_DSTODS(wh)) {
+ wh4 = mtod(m,
+ struct ieee80211_qosframe_addr4*);
+ *(uint16_t *)wh4->i_qos = ds->qosctrl;
+ } else {
+ *(uint16_t *)wh->i_qos = ds->qosctrl;
+ }
+ }
+ if (sc->malo_drvbpf != NULL) {
+ sc->malo_rx_th.wr_flags = 0;
+ sc->malo_rx_th.wr_rate = ds->rate;
+ sc->malo_rx_th.wr_antsignal = rssi;
+ sc->malo_rx_th.wr_antnoise = ds->nf;
+
+ bpf_mtap2(sc->malo_drvbpf,
+ &sc->malo_rx_th, sc->malo_rx_th_len, m);
+ }
+#ifdef MALO_DEBUG
+ if (IFF_DUMPPKTS_RECV(sc, wh)) {
+ ieee80211_dump_pkt(ic, mtod(m, caddr_t),
+ len, ds->rate, rssi);
+ }
+#endif
+ ifp->if_ipackets++;
+
+ /* dispatch */
+ ni = ieee80211_find_rxnode(ic,
+ (const struct ieee80211_frame_min *) wh);
+ (void) ieee80211_input(ic, m, ni, rssi, ds->nf, 0/*XXX*/);
+ ieee80211_free_node(ni);
+
+rx_next:
+ /* NB: ignore ENOMEM so we process more descriptors */
+ (void) malo_rxbuf_init(sc, bf);
+ bf = STAILQ_NEXT(bf, bf_list);
+ }
+
+ malo_bar0_write4(sc, sc->malo_hwspecs.rxdesc_read, readptr);
+ sc->malo_rxnext = bf;
+
+ if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0 &&
+ !IFQ_IS_EMPTY(&ifp->if_snd))
+ malo_start(ifp);
+#undef IEEE80211_DIR_DSTODS
+}
+
+static void
+malo_stop(struct ifnet *ifp, int disable)
+{
+ struct malo_softc *sc = ifp->if_softc;
+
+ MALO_LOCK(sc);
+
+ malo_stop_locked(ifp, disable);
+
+ MALO_UNLOCK(sc);
+}
+
+/*
+ * Reclaim all tx queue resources.
+ */
+static void
+malo_tx_cleanup(struct malo_softc *sc)
+{
+ int i;
+
+ for (i = 0; i < MALO_NUM_TX_QUEUES; i++)
+ malo_tx_cleanupq(sc, &sc->malo_txq[i]);
+}
+
+int
+malo_detach(struct malo_softc *sc)
+{
+ struct ifnet *ifp = sc->malo_ifp;
+
+ DPRINTF(sc, MALO_DEBUG_ANY, "%s: if_flags %x\n",
+ __func__, ifp->if_flags);
+
+ malo_stop(ifp, 1);
+
+ if (sc->malo_tq != NULL) {
+ taskqueue_drain(sc->malo_tq, &sc->malo_rxtask);
+ taskqueue_drain(sc->malo_tq, &sc->malo_txtask);
+ taskqueue_free(sc->malo_tq);
+ sc->malo_tq = NULL;
+ }
+
+ bpfdetach(ifp);
+
+ /*
+ * NB: the order of these is important:
+ * o call the 802.11 layer before detaching the hal to
+ * insure callbacks into the driver to delete global
+ * key cache entries can be handled
+ * o reclaim the tx queue data structures after calling
+ * the 802.11 layer as we'll get called back to reclaim
+ * node state and potentially want to use them
+ * o to cleanup the tx queues the hal is called, so detach
+ * it last
+ * Other than that, it's straightforward...
+ */
+ ieee80211_ifdetach(&sc->malo_ic);
+ malo_dma_cleanup(sc);
+ malo_tx_cleanup(sc);
+ malo_hal_detach(sc->malo_mh);
+ if_free(ifp);
+
+ MALO_LOCK_DESTROY(sc);
+
+ return 0;
+}
+
+void
+malo_shutdown(struct malo_softc *sc)
+{
+
+ malo_stop(sc->malo_ifp, 1);
+}
+
+void
+malo_suspend(struct malo_softc *sc)
+{
+ struct ifnet *ifp = sc->malo_ifp;
+
+ DPRINTF(sc, MALO_DEBUG_ANY, "%s: if_flags %x\n",
+ __func__, ifp->if_flags);
+
+ malo_stop(ifp, 1);
+}
+
+void
+malo_resume(struct malo_softc *sc)
+{
+ struct ifnet *ifp = sc->malo_ifp;
+
+ DPRINTF(sc, MALO_DEBUG_ANY, "%s: if_flags %x\n",
+ __func__, ifp->if_flags);
+
+ if (ifp->if_flags & IFF_UP) {
+ malo_init(sc);
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING)
+ malo_start(ifp);
+ }
+}
diff --git a/sys/dev/malo/if_malo.h b/sys/dev/malo/if_malo.h
new file mode 100644
index 0000000..0cb5bc6
--- /dev/null
+++ b/sys/dev/malo/if_malo.h
@@ -0,0 +1,586 @@
+/*-
+ * Copyright (c) 2007 Marvell Semiconductor, Inc.
+ * Copyright (c) 2007 Sam Leffler, Errno Consulting
+ * Copyright (c) 2008 Weongyo Jeong <weongyo@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ * redistribution must be conditioned upon including a substantially
+ * similar Disclaimer requirement for further binary redistribution.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Definitions for the Marvell 88W8335 Wireless LAN controller.
+ */
+#ifndef _DEV_MALO_H
+#define _DEV_MALO_H
+
+#include <net80211/ieee80211_radiotap.h>
+#include <dev/malo/if_malohal.h>
+#include <dev/malo/if_maloioctl.h>
+
+#ifndef MALO_TXBUF
+#define MALO_TXBUF 256 /* number of TX descriptors/buffers */
+#endif
+#ifndef MALO_RXBUF
+#define MALO_RXBUF 256 /* number of RX descriptors/buffers */
+#endif
+
+#define MALO_TXDESC 1 /* max tx descriptors/segments */
+
+#define MALO_RXSIZE PAGE_SIZE
+#define MALO_RSSI_DUMMY_MARKER 127
+#define MALO_RSSI_EP_MULTIPLIER (1<<7) /* pow2 to optimize out * and / */
+
+#define MALO_REG_INT_CODE 0x00000C14
+/* From host to ARM */
+#define MALO_REG_H2A_INTERRUPT_EVENTS 0x00000C18
+
+/* bit definitions for MALO_REG_H2A_INTERRUPT_CAUSE */
+#define MALO_H2ARIC_BIT_PPA_READY 0x00000001
+#define MALO_H2ARIC_BIT_DOOR_BELL 0x00000002 /* bit 1 */
+#define MALO_H2ARIC_BIT_PS 0x00000004
+#define MALO_H2ARIC_BIT_PSPOLL 0x00000008 /* bit 3 */
+
+/* From ARM to host */
+#define MALO_REG_A2H_INTERRUPT_CAUSE 0x00000C30
+#define MALO_REG_A2H_INTERRUPT_MASK 0x00000C34
+#define MALO_REG_A2H_INTERRUPT_CLEAR_SEL 0x00000C38
+#define MALO_REG_A2H_INTERRUPT_STATUS_MASK 0x00000C3C
+
+/* bit definitions for MALO_REG_A2H_INTERRUPT_CAUSE */
+#define MALO_A2HRIC_BIT_TX_DONE 0x00000001 /* bit 0 */
+#define MALO_A2HRIC_BIT_RX_RDY 0x00000002 /* bit 1 */
+#define MALO_A2HRIC_BIT_OPC_DONE 0x00000004
+#define MALO_A2HRIC_BIT_MAC_EVENT 0x00000008
+#define MALO_A2HRIC_BIT_RX_PROBLEM 0x00000010
+#define MALO_A2HRIC_BIT_RADIO_OFF 0x00000020 /* bit 5 */
+#define MALO_A2HRIC_BIT_RADIO_ON 0x00000040
+#define MALO_A2HRIC_BIT_RADAR_DETECT 0x00000080
+#define MALO_A2HRIC_BIT_ICV_ERROR 0x00000100
+#define MALO_A2HRIC_BIT_MIC_ERROR 0x00000200 /* bit 9 */
+#define MALO_A2HRIC_BIT_QUEUE_EMPTY 0x00000400
+#define MALO_A2HRIC_BIT_QUEUE_FULL 0x00000800
+#define MALO_A2HRIC_BIT_CHAN_SWITCH 0x00001000
+#define MALO_A2HRIC_BIT_TX_WATCHDOG 0x00002000
+#define MALO_A2HRIC_BIT_BA_WATCHDOG 0x00004000
+
+#define MALO_ISR_SRC_BITS \
+ (MALO_A2HRIC_BIT_RX_RDY | \
+ MALO_A2HRIC_BIT_TX_DONE | \
+ MALO_A2HRIC_BIT_OPC_DONE | \
+ MALO_A2HRIC_BIT_MAC_EVENT | \
+ MALO_A2HRIC_BIT_MIC_ERROR | \
+ MALO_A2HRIC_BIT_ICV_ERROR | \
+ MALO_A2HRIC_BIT_RADAR_DETECT | \
+ MALO_A2HRIC_BIT_CHAN_SWITCH | \
+ MALO_A2HRIC_BIT_TX_WATCHDOG | \
+ MALO_A2HRIC_BIT_QUEUE_EMPTY)
+#define MALO_ISR_RESET (1<<15)
+
+#define MALO_A2HRIC_BIT_MASK MALO_ISR_SRC_BITS
+
+/* map to 0x80000000 on BAR1 */
+#define MALO_REG_GEN_PTR 0x00000C10
+#define MALO_REG_INT_CODE 0x00000C14
+#define MALO_REG_SCRATCH 0x00000C40
+
+/*
+ * define OpMode for SoftAP/Station mode
+ *
+ * the following mode signature has to be written to PCI scratch register#0
+ * right after successfully downloading the last block of firmware and
+ * before waiting for firmware ready signature
+ */
+#define MALO_HOSTCMD_STA_MODE 0x5A
+#define MALO_HOSTCMD_STA_FWRDY_SIGNATURE 0xF0F1F2F4
+
+/*
+ * 16 bit host command code
+ */
+#define MALO_HOSTCMD_NONE 0x0000
+#define MALO_HOSTCMD_CODE_DNLD 0x0001
+#define MALO_HOSTCMD_GET_HW_SPEC 0x0003
+#define MALO_HOSTCMD_SET_HW_SPEC 0x0004
+#define MALO_HOSTCMD_MAC_MULTICAST_ADR 0x0010
+#define MALO_HOSTCMD_SET_WEPKEY 0x0013
+#define MALO_HOSTCMD_802_11_RADIO_CONTROL 0x001c
+#define MALO_HOSTCMD_802_11_RF_TX_POWER 0x001e
+#define MALO_HOSTCMD_802_11_RF_ANTENNA 0x0020
+#define MALO_HOSTCMD_SET_PRE_SCAN 0x0107
+#define MALO_HOSTCMD_SET_POST_SCAN 0x0108
+#define MALO_HOSTCMD_SET_RF_CHANNEL 0x010a
+#define MALO_HOSTCMD_SET_AID 0x010d
+#define MALO_HOSTCMD_SET_RATE 0x0110
+#define MALO_HOSTCMD_SET_SLOT 0x0114
+/* define DFS lab commands */
+#define MALO_HOSTCMD_SET_FIXED_RATE 0x0126
+#define MALO_HOSTCMD_SET_REGION_POWER 0x0128
+#define MALO_HOSTCMD_GET_CALTABLE 0x1134
+
+/*
+ * definition of action or option for each command.
+ */
+/* define general purpose action */
+#define MALO_HOSTCMD_ACT_GEN_GET 0x0000
+#define MALO_HOSTCMD_ACT_GEN_SET 0x0001
+#define MALO_HOSTCMD_ACT_GEN_SET_LIST 0x0002
+
+/* define action or option for HostCmd_FW_USE_FIXED_RATE */
+#define MALO_HOSTCMD_ACT_USE_FIXED_RATE 0x0001
+#define MALO_HOSTCMD_ACT_NOT_USE_FIXED_RATE 0x0002
+
+/* INT code register event definition */
+#define MALO_INT_CODE_CMD_FINISHED 0x00000005
+
+struct malo_cmd_header {
+ uint16_t cmd;
+ uint16_t length;
+ uint16_t seqnum;
+ uint16_t result;
+} __packed;
+
+struct malo_cmd_caltable {
+ struct malo_cmd_header cmdhdr;
+ uint8_t annex;
+ uint8_t index;
+ uint8_t len;
+ uint8_t reserverd;
+#define MALO_CAL_TBL_SIZE 160
+ uint8_t caltbl[MALO_CAL_TBL_SIZE];
+} __packed;
+
+struct malo_cmd_get_hwspec {
+ struct malo_cmd_header cmdhdr;
+ u_int8_t version; /* version of the HW */
+ u_int8_t hostif; /* host interface */
+ /* Max. number of WCB FW can handle */
+ u_int16_t num_wcb;
+ /* MaxNbr of MC addresses FW can handle */
+ u_int16_t num_mcastaddr;
+ /* MAC address programmed in HW */
+ u_int8_t permaddr[6];
+ u_int16_t regioncode;
+ /* Number of antenna used */
+ u_int16_t num_antenna;
+ /* 4 byte of FW release number */
+ u_int32_t fw_releasenum;
+ u_int32_t wcbbase0;
+ u_int32_t rxpdwr_ptr;
+ u_int32_t rxpdrd_ptr;
+ u_int32_t ul_fw_awakecookie;
+ u_int32_t wcbbase1;
+ u_int32_t wcbbase2;
+ u_int32_t wcbbase3;
+} __packed;
+
+struct malo_cmd_set_hwspec {
+ struct malo_cmd_header cmdhdr;
+ uint8_t version; /* HW revision */
+ uint8_t hostif; /* Host interface */
+ /* Max. number of Multicast address FW can handle */
+ uint16_t num_mcastaddr;
+ uint8_t permaddr[6]; /* MAC address */
+ uint16_t regioncode; /* Region Code */
+ /* 4 byte of FW release number */
+ uint32_t fwreleasenum;
+ /* Firmware awake cookie */
+ uint32_t ul_fw_awakecookie;
+ /* Device capabilities (see above) */
+ uint32_t devicecaps;
+ uint32_t rxpdwrptr; /* Rx shared memory queue */
+ /* # TX queues in WcbBase array */
+ uint32_t num_txqueues;
+ /* TX WCB Rings */
+ uint32_t wcbbase[MALO_MAX_TXWCB_QUEUES];
+ uint32_t flags;
+ uint32_t txwcbnum_per_queue;
+ uint32_t total_rxwcb;
+} __packed;
+
+/* DS 802.11 */
+struct malo_cmd_rf_antenna {
+ struct malo_cmd_header cmdhdr;
+ uint16_t action;
+ /* Number of antennas or 0xffff (diversity) */
+ uint16_t mode;
+} __packed;
+
+struct malo_cmd_radio_control {
+ struct malo_cmd_header cmdhdr;
+ uint16_t action;
+ /*
+ * bit 0 : 1 = on, 0 = off
+ * bit 1 : 1 = long, 0 = short
+ * bit 2 : 1 = auto, 0 = fix
+ */
+ uint16_t control;
+ uint16_t radio_on;
+} __packed;
+
+struct malo_cmd_fw_set_wmmmode {
+ struct malo_cmd_header cmdhdr;
+ uint16_t action; /* 0 -> unset, 1 -> set */
+} __packed;
+
+struct malo_cmd_fw_set_rf_channel {
+ struct malo_cmd_header cmdhdr;
+ uint16_t action;
+ uint8_t cur_channel; /* channel # */
+} __packed;
+
+#define MALO_TX_POWER_LEVEL_TOTAL 8
+struct malo_cmd_rf_tx_power {
+ struct malo_cmd_header cmdhdr;
+ uint16_t action;
+ uint16_t support_txpower_level;
+ uint16_t current_txpower_level;
+ uint16_t reserved;
+ uint16_t power_levellist[MALO_TX_POWER_LEVEL_TOTAL];
+} __packed;
+
+struct malo_fixrate_flag {
+ /* lower rate after the retry count. 0 = legacy, 1 = HT */
+ uint32_t type;
+ /* 0: retry count is not valid, 1: use retry count specified */
+ uint32_t retrycount_valid;
+} __packed;
+
+struct malo_fixed_rate_entry {
+ struct malo_fixrate_flag typeflags;
+ /* legacy rate(not index) or an MCS code. */
+ uint32_t fixedrate;
+ uint32_t retrycount;
+} __packed;
+
+struct malo_cmd_fw_use_fixed_rate {
+ struct malo_cmd_header cmdhdr;
+ /*
+ * MALO_HOSTCMD_ACT_GEN_GET 0x0000
+ * MALO_HOSTCMD_ACT_GEN_SET 0x0001
+ * MALO_HOSTCMD_ACT_NOT_USE_FIXED_RATE 0x0002
+ */
+ uint32_t action;
+ /* use fixed rate specified but firmware can drop to */
+ uint32_t allowratedrop;
+ uint32_t entrycount;
+ struct malo_fixed_rate_entry fixedrate_table[4];
+ uint8_t multicast_rate;
+ uint8_t multirate_txtype;
+ uint8_t management_rate;
+} __packed;
+
+#define MALO_RATE_INDEX_MAX_ARRAY 14
+
+struct malo_cmd_fw_set_aid {
+ struct malo_cmd_header cmdhdr;
+ uint16_t associd;
+ uint8_t macaddr[6]; /* AP's Mac Address(BSSID) */
+ uint32_t gprotection;
+ uint8_t aprates[MALO_RATE_INDEX_MAX_ARRAY];
+} __packed;
+
+struct malo_cmd_prescan {
+ struct malo_cmd_header cmdhdr;
+} __packed;
+
+struct malo_cmd_postscan {
+ struct malo_cmd_header cmdhdr;
+ uint32_t isibss;
+ uint8_t bssid[6];
+} __packed;
+
+struct malo_cmd_fw_setslot {
+ struct malo_cmd_header cmdhdr;
+ uint16_t action;
+ /* slot = 0 if regular, slot = 1 if short. */
+ uint8_t slot;
+};
+
+struct malo_cmd_set_rate {
+ struct malo_cmd_header cmdhdr;
+ uint8_t dataratetype;
+ uint8_t rateindex;
+ uint8_t aprates[14];
+} __packed;
+
+struct malo_cmd_wepkey {
+ struct malo_cmd_header cmdhdr;
+ uint16_t action;
+ uint8_t len;
+ uint8_t flags;
+ uint16_t index;
+ uint8_t value[IEEE80211_KEYBUF_SIZE];
+ uint8_t txmickey[IEEE80211_WEP_MICLEN];
+ uint8_t rxmickey[IEEE80211_WEP_MICLEN];
+ uint64_t rxseqctr;
+ uint64_t txseqctr;
+} __packed;
+
+struct malo_cmd_mcast {
+ struct malo_cmd_header cmdhdr;
+ uint16_t action;
+ uint16_t numaddr;
+#define MALO_HAL_MCAST_MAX 32
+ uint8_t maclist[6*32];
+} __packed;
+
+/*
+ * DMA state for tx/rx descriptors.
+ */
+
+/*
+ * Common "base class" for tx/rx descriptor resources
+ * allocated using the bus dma api.
+ */
+struct malo_descdma {
+ const char* dd_name;
+ void *dd_desc; /* descriptors */
+ bus_addr_t dd_desc_paddr; /* physical addr of dd_desc */
+ bus_size_t dd_desc_len; /* size of dd_desc */
+ bus_dma_segment_t dd_dseg;
+ int dd_dnseg; /* number of segments */
+ bus_dma_tag_t dd_dmat; /* bus DMA tag */
+ bus_dmamap_t dd_dmamap; /* DMA map for descriptors */
+ void *dd_bufptr; /* associated buffers */
+};
+
+/*
+ * Hardware tx/rx descriptors.
+ *
+ * NB: tx descriptor size must match f/w expected size
+ * because f/w prefetch's the next descriptor linearly
+ * and doesn't chase the next pointer.
+ */
+struct malo_txdesc {
+ uint32_t status;
+#define MALO_TXD_STATUS_IDLE 0x00000000
+#define MALO_TXD_STATUS_USED 0x00000001
+#define MALO_TXD_STATUS_OK 0x00000001
+#define MALO_TXD_STATUS_OK_RETRY 0x00000002
+#define MALO_TXD_STATUS_OK_MORE_RETRY 0x00000004
+#define MALO_TXD_STATUS_MULTICAST_TX 0x00000008
+#define MALO_TXD_STATUS_BROADCAST_TX 0x00000010
+#define MALO_TXD_STATUS_FAILED_LINK_ERROR 0x00000020
+#define MALO_TXD_STATUS_FAILED_EXCEED_LIMIT 0x00000040
+#define MALO_TXD_STATUS_FAILED_XRETRY MALO_TXD_STATUS_FAILED_EXCEED_LIMIT
+#define MALO_TXD_STATUS_FAILED_AGING 0x00000080
+#define MALO_TXD_STATUS_FW_OWNED 0x80000000
+ uint8_t datarate;
+ uint8_t txpriority;
+ uint16_t qosctrl;
+ uint32_t pktptr;
+ uint16_t pktlen;
+ uint8_t destaddr[6];
+ uint32_t physnext;
+ uint32_t sap_pktinfo;
+ uint16_t format;
+#define MALO_TXD_FORMAT 0x0001 /* frame format/rate */
+#define MALO_TXD_FORMAT_LEGACY 0x0000 /* legacy rate frame */
+#define MALO_TXD_RATE 0x01f8 /* tx rate (legacy)/ MCS */
+#define MALO_TXD_RATE_S 3
+/* NB: 3 is reserved */
+#define MALO_TXD_ANTENNA 0x1800 /* antenna select */
+#define MALO_TXD_ANTENNA_S 11
+ uint16_t pad; /* align to 4-byte boundary */
+} __packed;
+
+#define MALO_TXDESC_SYNC(txq, ds, how) do { \
+ bus_dmamap_sync((txq)->dma.dd_dmat, (txq)->dma.dd_dmamap, how); \
+} while(0)
+
+struct malo_rxdesc {
+ uint8_t rxcontrol; /* control element */
+#define MALO_RXD_CTRL_DRIVER_OWN 0x00
+#define MALO_RXD_CTRL_OS_OWN 0x04
+#define MALO_RXD_CTRL_DMA_OWN 0x80
+ uint8_t snr; /* signal to noise ratio */
+ uint8_t status; /* status field w/ USED bit */
+#define MALO_RXD_STATUS_IDLE 0x00
+#define MALO_RXD_STATUS_OK 0x01
+#define MALO_RXD_STATUS_MULTICAST_RX 0x02
+#define MALO_RXD_STATUS_BROADCAST_RX 0x04
+#define MALO_RXD_STATUS_FRAGMENT_RX 0x08
+#define MALO_RXD_STATUS_GENERAL_DECRYPT_ERR 0xff
+#define MALO_RXD_STATUS_DECRYPT_ERR_MASK 0x80
+#define MALO_RXD_STATUS_TKIP_MIC_DECRYPT_ERR 0x02
+#define MALO_RXD_STATUS_WEP_ICV_DECRYPT_ERR 0x04
+#define MALO_RXD_STATUS_TKIP_ICV_DECRYPT_ERR 0x08
+ uint8_t channel; /* channel # pkt received on */
+ uint16_t pktlen; /* total length of received data */
+ uint8_t nf; /* noise floor */
+ uint8_t rate; /* received data rate */
+ uint32_t physbuffdata; /* physical address of payload data */
+ uint32_t physnext; /* physical address of next RX desc */
+ uint16_t qosctrl; /* received QosCtrl field variable */
+ uint16_t htsig2; /* like name states */
+} __packed;
+
+#define MALO_RXDESC_SYNC(sc, ds, how) do { \
+ bus_dmamap_sync((sc)->malo_rxdma.dd_dmat, \
+ (sc)->malo_rxdma.dd_dmamap, how); \
+} while (0)
+
+struct malo_rxbuf {
+ STAILQ_ENTRY(malo_rxbuf) bf_list;
+ void *bf_desc; /* h/w descriptor */
+ bus_addr_t bf_daddr; /* physical addr of desc */
+ bus_dmamap_t bf_dmamap;
+ bus_addr_t bf_data; /* physical addr of rx data */
+ struct mbuf *bf_m; /* jumbo mbuf */
+};
+typedef STAILQ_HEAD(, malo_rxbuf) malo_rxbufhead;
+
+/*
+ * Software backed version of tx/rx descriptors. We keep
+ * the software state out of the h/w descriptor structure
+ * so that may be allocated in uncached memory w/o paying
+ * performance hit.
+ */
+struct malo_txbuf {
+ STAILQ_ENTRY(malo_txbuf) bf_list;
+ void *bf_desc; /* h/w descriptor */
+ bus_addr_t bf_daddr; /* physical addr of desc */
+ bus_dmamap_t bf_dmamap; /* DMA map for descriptors */
+ int bf_nseg;
+ bus_dma_segment_t bf_segs[MALO_TXDESC];
+ struct mbuf *bf_m;
+ struct ieee80211_node *bf_node;
+ struct malo_txq *bf_txq; /* backpointer to tx q/ring */
+};
+typedef STAILQ_HEAD(, malo_txbuf) malo_txbufhead;
+
+/*
+ * TX/RX ring definitions. There are 4 tx rings, one
+ * per AC, and 1 rx ring. Note carefully that transmit
+ * descriptors are treated as a contiguous chunk and the
+ * firmware pre-fetches descriptors. This means that we
+ * must preserve order when moving descriptors between
+ * the active+free lists; otherwise we may stall transmit.
+ */
+struct malo_txq {
+ struct malo_descdma dma; /* bus dma resources */
+ struct mtx lock; /* tx q lock */
+ char name[12]; /* e.g. "malo0_txq4" */
+ int qnum; /* f/w q number */
+ int txpri; /* f/w tx priority */
+ int nfree; /* # buffers on free list */
+ malo_txbufhead free; /* queue of free buffers */
+ malo_txbufhead active; /* queue of active buffers */
+};
+
+#define MALO_TXQ_LOCK_INIT(_sc, _tq) do { \
+ snprintf((_tq)->name, sizeof((_tq)->name), "%s_txq%u", \
+ device_get_nameunit((_sc)->malo_dev), (_tq)->qnum); \
+ mtx_init(&(_tq)->lock, (_tq)->name, NULL, MTX_DEF); \
+} while (0)
+#define MALO_TXQ_LOCK_DESTROY(_tq) mtx_destroy(&(_tq)->lock)
+#define MALO_TXQ_LOCK(_tq) mtx_lock(&(_tq)->lock)
+#define MALO_TXQ_UNLOCK(_tq) mtx_unlock(&(_tq)->lock)
+#define MALO_TXQ_LOCK_ASSERT(_tq) mtx_assert(&(_tq)->lock, MA_OWNED)
+
+/*
+ * Each packet has fixed front matter: a 2-byte length
+ * of the payload, followed by a 4-address 802.11 header
+ * (regardless of the actual header and always w/o any
+ * QoS header). The payload then follows.
+ */
+struct malo_txrec {
+ uint16_t fwlen;
+ struct ieee80211_frame_addr4 wh;
+} __packed;
+
+struct malo_softc {
+ struct ieee80211com malo_ic; /* IEEE 802.11 common */
+ device_t malo_dev;
+ struct ifnet *malo_ifp; /* interface common */
+ struct mtx malo_mtx; /* master lock (recursive) */
+ struct taskqueue *malo_tq; /* private task queue */
+
+ bus_dma_tag_t malo_dmat; /* bus DMA tag */
+ bus_space_handle_t malo_io0h; /* BAR 0 */
+ bus_space_tag_t malo_io0t;
+ bus_space_handle_t malo_io1h; /* BAR 1 */
+ bus_space_tag_t malo_io1t;
+
+ unsigned int malo_invalid : 1,/* disable hardware accesses */
+ malo_recvsetup : 1, /* recv setup */
+ malo_fixedrate : 1, /* use fixed tx rate */
+ malo_fw_loaded : 1; /* fw loaded */
+
+ struct malo_hal *malo_mh; /* h/w access layer */
+ struct malo_hal_hwspec malo_hwspecs; /* h/w capabilities */
+ struct malo_hal_txrxdma malo_hwdma; /* h/w dma setup */
+ uint32_t malo_imask; /* interrupt mask copy */
+ struct malo_hal_channel malo_curchan;
+ u_int16_t malo_rxantenna; /* rx antenna */
+ u_int16_t malo_txantenna; /* tx antenna */
+
+ struct malo_descdma malo_rxdma; /* rx bus dma resources */
+ malo_rxbufhead malo_rxbuf; /* rx buffers */
+ struct malo_rxbuf *malo_rxnext; /* next rx buffer to process */
+ struct task malo_rxtask; /* rx int processing */
+
+ struct malo_txq malo_txq[MALO_NUM_TX_QUEUES];
+ struct task malo_txtask; /* tx int processing */
+
+ int (*malo_newstate)(struct ieee80211com *,
+ enum ieee80211_state, int);
+
+ struct bpf_if *malo_drvbpf;
+ struct malo_tx_radiotap_header malo_tx_th;
+ int malo_tx_th_len;
+ struct malo_rx_radiotap_header malo_rx_th;
+ int malo_rx_th_len;
+
+ struct malo_stats malo_stats; /* interface statistics */
+ int malo_debug;
+};
+
+#define MALO_LOCK_INIT(_sc) \
+ mtx_init(&(_sc)->malo_mtx, device_get_nameunit((_sc)->malo_dev), \
+ NULL, MTX_DEF | MTX_RECURSE)
+#define MALO_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->malo_mtx)
+#define MALO_LOCK(_sc) mtx_lock(&(_sc)->malo_mtx)
+#define MALO_UNLOCK(_sc) mtx_unlock(&(_sc)->malo_mtx)
+#define MALO_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->malo_mtx, MA_OWNED)
+
+#define MALO_RXFREE_INIT(_sc) \
+ mtx_init(&(_sc)->malo_rxlock, device_get_nameunit((_sc)->malo_dev), \
+ NULL, MTX_DEF)
+#define MALO_RXFREE_DESTROY(_sc) mtx_destroy(&(_sc)->malo_rxlock)
+#define MALO_RXFREE_LOCK(_sc) mtx_lock(&(_sc)->malo_rxlock)
+#define MALO_RXFREE_UNLOCK(_sc) mtx_unlock(&(_sc)->malo_rxlock)
+#define MALO_RXFREE_ASSERT(_sc) mtx_assert(&(_sc)->malo_rxlock, \
+ MA_OWNED)
+
+int malo_attach(uint16_t, struct malo_softc *);
+int malo_intr(void *);
+int malo_detach(struct malo_softc *);
+void malo_shutdown(struct malo_softc *);
+void malo_suspend(struct malo_softc *);
+void malo_resume(struct malo_softc *);
+
+#endif
diff --git a/sys/dev/malo/if_malo_pci.c b/sys/dev/malo/if_malo_pci.c
new file mode 100644
index 0000000..a4c8e51
--- /dev/null
+++ b/sys/dev/malo/if_malo_pci.c
@@ -0,0 +1,373 @@
+/*-
+ * Copyright (c) 2007 Marvell Semiconductor, Inc.
+ * Copyright (c) 2007 Sam Leffler, Errno Consulting
+ * Copyright (c) 2008 Weongyo Jeong <weongyo@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ * redistribution must be conditioned upon including a substantially
+ * similar Disclaimer requirement for further binary redistribution.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <sys/cdefs.h>
+#ifdef __FreeBSD__
+__FBSDID("$FreeBSD$");
+#endif
+
+/*
+ * PCI front-end for the Marvell 88W8335 Wireless LAN controller driver.
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <machine/bus.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+
+#include <dev/malo/if_malo.h>
+
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+
+/*
+ * PCI glue.
+ */
+
+#define MALO_RESOURCE_MAX 2
+#define MALO_MSI_MESSAGES 1
+
+struct malo_pci_softc {
+ struct malo_softc malo_sc;
+ struct resource_spec *malo_mem_spec;
+ struct resource *malo_res_mem[MALO_RESOURCE_MAX];
+ struct resource_spec *malo_irq_spec;
+ struct resource *malo_res_irq[MALO_MSI_MESSAGES];
+ void *malo_intrhand[MALO_MSI_MESSAGES];
+ int malo_msi;
+};
+
+/*
+ * Tunable variables.
+ */
+SYSCTL_DECL(_hw_malo);
+SYSCTL_NODE(_hw_malo, OID_AUTO, pci, CTLFLAG_RD, 0,
+ "Marvell 88W8335 driver PCI parameters");
+
+static int msi_disable = 0; /* MSI disabled */
+SYSCTL_INT(_hw_malo_pci, OID_AUTO, msi_disable, CTLFLAG_RW, &msi_disable,
+ 0, "MSI disabled");
+TUNABLE_INT("hw.malo.pci.msi_disable", &msi_disable);
+
+/*
+ * Devices supported by this driver.
+ */
+#define VENDORID_MARVELL 0X11AB
+#define DEVICEID_MRVL_88W8310 0X1FA7
+#define DEVICEID_MRVL_88W8335R1 0X1FAA
+#define DEVICEID_MRVL_88W8335R2 0X1FAB
+
+static struct malo_product {
+ uint16_t mp_vendorid;
+ uint16_t mp_deviceid;
+ const char *mp_name;
+} malo_products[] = {
+ { VENDORID_MARVELL, DEVICEID_MRVL_88W8310,
+ "Marvell Libertas 88W8310 802.11g Wireless Adapter" },
+ { VENDORID_MARVELL, DEVICEID_MRVL_88W8335R1,
+ "Marvell Libertas 88W8335 802.11g Wireless Adapter" },
+ { VENDORID_MARVELL, DEVICEID_MRVL_88W8335R2,
+ "Marvell Libertas 88W8335 802.11g Wireless Adapter" }
+};
+
+static struct resource_spec malo_res_spec_mem[] = {
+ { SYS_RES_MEMORY, PCIR_BAR(0), RF_ACTIVE },
+ { SYS_RES_MEMORY, PCIR_BAR(1), RF_ACTIVE },
+ { -1, 0, 0 }
+};
+
+static struct resource_spec malo_res_spec_legacy[] = {
+ { SYS_RES_IRQ, 0, RF_ACTIVE | RF_SHAREABLE },
+ { -1, 0, 0 }
+};
+
+static struct resource_spec malo_res_spec_msi[] = {
+ { SYS_RES_IRQ, 1, RF_ACTIVE },
+ { -1, 0, 0 }
+};
+
+static int malo_pci_detach(device_t);
+
+static int
+malo_pci_probe(device_t dev)
+{
+#define N(a) (sizeof(a) / sizeof((a)[0]))
+ struct malo_product *mp;
+ uint16_t vendor, devid;
+ int i;
+
+ vendor = pci_get_vendor(dev);
+ devid = pci_get_device(dev);
+ mp = malo_products;
+
+ for (i = 0; i < N(malo_products); i++, mp++) {
+ if (vendor == mp->mp_vendorid && devid == mp->mp_deviceid) {
+ device_set_desc(dev, mp->mp_name);
+ return (BUS_PROBE_DEFAULT);
+ }
+ }
+
+ return (ENXIO);
+#undef N
+}
+
+static int
+malo_pci_setup(device_t dev)
+{
+
+ /*
+ * Enable memory mapping and bus mastering.
+ */
+ if (pci_enable_busmaster(dev) != 0)
+ return -1;
+ if (pci_enable_io(dev, SYS_RES_MEMORY) != 0)
+ return -1;
+
+ return 0;
+}
+
+static int
+malo_pci_attach(device_t dev)
+{
+ int error = ENXIO, i, msic, reg;
+ struct malo_pci_softc *psc = device_get_softc(dev);
+ struct malo_softc *sc = &psc->malo_sc;
+
+ sc->malo_dev = dev;
+
+ /*
+ * Enable memory mapping and bus mastering.
+ */
+ if (malo_pci_setup(dev))
+ return (ENXIO);
+
+ /*
+ * Setup memory-mapping of PCI registers.
+ */
+ psc->malo_mem_spec = malo_res_spec_mem;
+ error = bus_alloc_resources(dev, psc->malo_mem_spec, psc->malo_res_mem);
+ if (error) {
+ device_printf(dev, "couldn't allocate memory resources\n");
+ return (ENXIO);
+ }
+
+ /*
+ * Arrange and allocate interrupt line.
+ */
+ sc->malo_invalid = 1;
+
+ if (pci_find_extcap(dev, PCIY_EXPRESS, &reg) == 0) {
+ msic = pci_msi_count(dev);
+ if (bootverbose)
+ device_printf(dev, "MSI count : %d\n", msic);
+ } else
+ msic = 0;
+
+ psc->malo_irq_spec = malo_res_spec_legacy;
+ if (msic == MALO_MSI_MESSAGES && msi_disable == 0) {
+ if (pci_alloc_msi(dev, &msic) == 0) {
+ if (msic == MALO_MSI_MESSAGES) {
+ device_printf(dev, "Using %d MSI messages\n",
+ msic);
+ psc->malo_irq_spec = malo_res_spec_msi;
+ psc->malo_msi = 1;
+ } else
+ pci_release_msi(dev);
+ }
+ }
+
+ error = bus_alloc_resources(dev, psc->malo_irq_spec, psc->malo_res_irq);
+ if (error) {
+ device_printf(dev, "couldn't allocate IRQ resources\n");
+ goto bad;
+ }
+
+ if (psc->malo_msi == 0)
+ error = bus_setup_intr(dev, psc->malo_res_irq[0],
+ INTR_TYPE_NET | INTR_MPSAFE, malo_intr, NULL, sc,
+ &psc->malo_intrhand[0]);
+ else {
+ for (i = 0; i < MALO_MSI_MESSAGES; i++) {
+ error = bus_setup_intr(dev, psc->malo_res_irq[i],
+ INTR_TYPE_NET | INTR_MPSAFE, malo_intr, NULL, sc,
+ &psc->malo_intrhand[i]);
+ if (error != 0)
+ break;
+ }
+ }
+
+ /*
+ * Setup DMA descriptor area.
+ */
+ if (bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */
+ 1, 0, /* alignment, bounds */
+ BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ BUS_SPACE_MAXADDR, /* maxsize */
+ 0, /* nsegments */
+ BUS_SPACE_MAXADDR, /* maxsegsize */
+ BUS_DMA_ALLOCNOW, /* flags */
+ NULL, /* lockfunc */
+ NULL, /* lockarg */
+ &sc->malo_dmat)) {
+ device_printf(dev, "cannot allocate DMA tag\n");
+ goto bad1;
+ }
+
+ sc->malo_io0t = rman_get_bustag(psc->malo_res_mem[0]);
+ sc->malo_io0h = rman_get_bushandle(psc->malo_res_mem[0]);
+ sc->malo_io1t = rman_get_bustag(psc->malo_res_mem[1]);
+ sc->malo_io1h = rman_get_bushandle(psc->malo_res_mem[1]);
+
+ error = malo_attach(pci_get_device(dev), sc);
+
+ if (error != 0) {
+ malo_pci_detach(dev);
+ return (error);
+ }
+
+ return (error);
+bad1:
+ if (psc->malo_msi == 0)
+ bus_teardown_intr(dev, psc->malo_res_irq[0],
+ psc->malo_intrhand[0]);
+ else {
+ for (i = 0; i < MALO_MSI_MESSAGES; i++)
+ bus_teardown_intr(dev, psc->malo_res_irq[i],
+ psc->malo_intrhand[i]);
+ }
+
+bad:
+ if (psc->malo_msi != 0)
+ pci_release_msi(dev);
+
+ return (error);
+}
+
+static int
+malo_pci_detach(device_t dev)
+{
+ int i;
+ struct malo_pci_softc *psc = device_get_softc(dev);
+ struct malo_softc *sc = &psc->malo_sc;
+
+ /* check if device was removed */
+ sc->malo_invalid = !bus_child_present(dev);
+
+ malo_detach(sc);
+
+ bus_generic_detach(dev);
+
+ if (psc->malo_msi == 0)
+ bus_teardown_intr(dev, psc->malo_res_irq[0],
+ psc->malo_intrhand[0]);
+ else {
+ for (i = 0; i < MALO_MSI_MESSAGES; i++)
+ bus_teardown_intr(dev, psc->malo_res_irq[i],
+ psc->malo_intrhand[i]);
+
+ pci_release_msi(dev);
+ }
+
+ bus_release_resources(dev, psc->malo_irq_spec, psc->malo_res_irq);
+ bus_dma_tag_destroy(sc->malo_dmat);
+ bus_release_resources(dev, psc->malo_mem_spec, psc->malo_res_mem);
+
+ return (0);
+}
+
+static int
+malo_pci_shutdown(device_t dev)
+{
+ struct malo_pci_softc *psc = device_get_softc(dev);
+
+ malo_shutdown(&psc->malo_sc);
+
+ return (0);
+}
+
+static int
+malo_pci_suspend(device_t dev)
+{
+ struct malo_pci_softc *psc = device_get_softc(dev);
+
+ malo_suspend(&psc->malo_sc);
+
+ return (0);
+}
+
+static int
+malo_pci_resume(device_t dev)
+{
+ struct malo_pci_softc *psc = device_get_softc(dev);
+
+ if (!malo_pci_setup(dev))
+ return ENXIO;
+
+ malo_resume(&psc->malo_sc);
+
+ return (0);
+}
+
+static device_method_t malo_pci_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, malo_pci_probe),
+ DEVMETHOD(device_attach, malo_pci_attach),
+ DEVMETHOD(device_detach, malo_pci_detach),
+ DEVMETHOD(device_shutdown, malo_pci_shutdown),
+ DEVMETHOD(device_suspend, malo_pci_suspend),
+ DEVMETHOD(device_resume, malo_pci_resume),
+ { 0,0 }
+};
+
+static driver_t malo_pci_driver = {
+ "malo",
+ malo_pci_methods,
+ sizeof(struct malo_pci_softc)
+};
+
+static devclass_t malo_devclass;
+DRIVER_MODULE(if_malo, pci, malo_pci_driver, malo_devclass, 0, 0);
+DRIVER_MODULE(if_malo, cardbus, malo_pci_driver, malo_devclass, 0, 0);
+MODULE_VERSION(if_malo, 1);
+MODULE_DEPEND(if_malo, wlan, 1, 1, 1); /* 802.11 media layer */
+MODULE_DEPEND(if_malo, malofw_fw, 1, 1, 1);
diff --git a/sys/dev/malo/if_malohal.c b/sys/dev/malo/if_malohal.c
new file mode 100644
index 0000000..f1c8c7b
--- /dev/null
+++ b/sys/dev/malo/if_malohal.c
@@ -0,0 +1,918 @@
+/*-
+ * Copyright (c) 2007 Marvell Semiconductor, Inc.
+ * Copyright (c) 2007 Sam Leffler, Errno Consulting
+ * Copyright (c) 2008 Weongyo Jeong <weongyo@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ * redistribution must be conditioned upon including a substantially
+ * similar Disclaimer requirement for further binary redistribution.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <sys/cdefs.h>
+#ifdef __FreeBSD__
+__FBSDID("$FreeBSD$");
+#endif
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/endian.h>
+#include <sys/kernel.h>
+#include <sys/firmware.h>
+#include <sys/socket.h>
+
+#include <machine/bus.h>
+#include <sys/bus.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+
+#include <net80211/ieee80211_var.h>
+
+#include <dev/malo/if_malo.h>
+
+#define MALO_WAITOK 1
+#define MALO_NOWAIT 0
+
+#define _CMD_SETUP(pCmd, _type, _cmd) do { \
+ pCmd = (_type *)&mh->mh_cmdbuf[0]; \
+ memset(pCmd, 0, sizeof(_type)); \
+ pCmd->cmdhdr.cmd = htole16(_cmd); \
+ pCmd->cmdhdr.length = htole16(sizeof(_type)); \
+} while (0)
+
+static __inline uint32_t
+malo_hal_read4(struct malo_hal *mh, bus_size_t off)
+{
+ return bus_space_read_4(mh->mh_iot, mh->mh_ioh, off);
+}
+
+static __inline void
+malo_hal_write4(struct malo_hal *mh, bus_size_t off, uint32_t val)
+{
+ bus_space_write_4(mh->mh_iot, mh->mh_ioh, off, val);
+}
+
+static void
+malo_hal_load_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
+{
+ bus_addr_t *paddr = (bus_addr_t*) arg;
+
+ KASSERT(error == 0, ("error %u on bus_dma callback", error));
+ *paddr = segs->ds_addr;
+}
+
+/*
+ * Setup for communication with the device. We allocate
+ * a command buffer and map it for bus dma use. The pci
+ * device id is used to identify whether the device has
+ * SRAM on it (in which case f/w download must include a
+ * memory controller reset). All bus i/o operations happen
+ * in BAR 1; the driver passes in the tag and handle we need.
+ */
+struct malo_hal *
+malo_hal_attach(device_t dev, uint16_t devid,
+ bus_space_handle_t ioh, bus_space_tag_t iot, bus_dma_tag_t tag)
+{
+ int error;
+ struct malo_hal *mh;
+
+ mh = malloc(sizeof(struct malo_hal), M_DEVBUF, M_NOWAIT | M_ZERO);
+ if (mh == NULL)
+ return NULL;
+
+ mh->mh_dev = dev;
+ mh->mh_ioh = ioh;
+ mh->mh_iot = iot;
+
+ snprintf(mh->mh_mtxname, sizeof(mh->mh_mtxname),
+ "%s_hal", device_get_nameunit(dev));
+ mtx_init(&mh->mh_mtx, mh->mh_mtxname, NULL, MTX_DEF);
+
+ /*
+ * Allocate the command buffer and map into the address
+ * space of the h/w. We request "coherent" memory which
+ * will be uncached on some architectures.
+ */
+ error = bus_dma_tag_create(tag, /* parent */
+ PAGE_SIZE, 0, /* alignment, bounds */
+ BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ MALO_CMDBUF_SIZE, /* maxsize */
+ 1, /* nsegments */
+ MALO_CMDBUF_SIZE, /* maxsegsize */
+ BUS_DMA_ALLOCNOW, /* flags */
+ NULL, /* lockfunc */
+ NULL, /* lockarg */
+ &mh->mh_dmat);
+ if (error != 0) {
+ device_printf(dev, "unable to allocate memory for cmd buffer, "
+ "error %u\n", error);
+ goto fail;
+ }
+
+ /* allocate descriptors */
+ error = bus_dmamap_create(mh->mh_dmat, BUS_DMA_NOWAIT, &mh->mh_dmamap);
+ if (error != 0) {
+ device_printf(dev, "unable to create dmamap for cmd buffers, "
+ "error %u\n", error);
+ goto fail;
+ }
+
+ error = bus_dmamem_alloc(mh->mh_dmat, (void**) &mh->mh_cmdbuf,
+ BUS_DMA_NOWAIT | BUS_DMA_COHERENT,
+ &mh->mh_dmamap);
+ if (error != 0) {
+ device_printf(dev, "unable to allocate memory for cmd buffer, "
+ "error %u\n", error);
+ goto fail;
+ }
+
+ error = bus_dmamap_load(mh->mh_dmat, mh->mh_dmamap,
+ mh->mh_cmdbuf, MALO_CMDBUF_SIZE,
+ malo_hal_load_cb, &mh->mh_cmdaddr,
+ BUS_DMA_NOWAIT);
+ if (error != 0) {
+ device_printf(dev, "unable to load cmd buffer, error %u\n",
+ error);
+ goto fail;
+ }
+
+ return (mh);
+
+fail:
+ free(mh, M_DEVBUF);
+
+ if (mh->mh_dmamap != NULL) {
+ bus_dmamap_unload(mh->mh_dmat, mh->mh_dmamap);
+ if (mh->mh_cmdbuf != NULL)
+ bus_dmamem_free(mh->mh_dmat, mh->mh_cmdbuf,
+ mh->mh_dmamap);
+ bus_dmamap_destroy(mh->mh_dmat, mh->mh_dmamap);
+ }
+ if (mh->mh_dmat)
+ bus_dma_tag_destroy(mh->mh_dmat);
+
+ return (NULL);
+}
+
+/*
+ * Low level firmware cmd block handshake support.
+ */
+
+static void
+malo_hal_send_cmd(struct malo_hal *mh)
+{
+ uint32_t dummy;
+
+ bus_dmamap_sync(mh->mh_dmat, mh->mh_dmamap,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+ malo_hal_write4(mh, MALO_REG_GEN_PTR, mh->mh_cmdaddr);
+ dummy = malo_hal_read4(mh, MALO_REG_INT_CODE);
+
+ malo_hal_write4(mh, MALO_REG_H2A_INTERRUPT_EVENTS,
+ MALO_H2ARIC_BIT_DOOR_BELL);
+}
+
+static int
+malo_hal_waitforcmd(struct malo_hal *mh, uint16_t cmd)
+{
+#define MAX_WAIT_FW_COMPLETE_ITERATIONS 10000
+ int i;
+
+ for (i = 0; i < MAX_WAIT_FW_COMPLETE_ITERATIONS; i++) {
+ if (mh->mh_cmdbuf[0] == le16toh(cmd))
+ return 1;
+
+ DELAY(1 * 1000);
+ }
+
+ return 0;
+#undef MAX_WAIT_FW_COMPLETE_ITERATIONS
+}
+
+static int
+malo_hal_execute_cmd(struct malo_hal *mh, unsigned short cmd)
+{
+ MALO_HAL_LOCK_ASSERT(mh);
+
+ if ((mh->mh_flags & MHF_FWHANG) &&
+ (mh->mh_debug & MALO_HAL_DEBUG_IGNHANG) == 0) {
+ device_printf(mh->mh_dev, "firmware hung, skipping cmd 0x%x\n",
+ cmd);
+ return ENXIO;
+ }
+
+ if (malo_hal_read4(mh, MALO_REG_INT_CODE) == 0xffffffff) {
+ device_printf(mh->mh_dev, "%s: device not present!\n",
+ __func__);
+ return EIO;
+ }
+
+ malo_hal_send_cmd(mh);
+ if (!malo_hal_waitforcmd(mh, cmd | 0x8000)) {
+ device_printf(mh->mh_dev,
+ "timeout waiting for f/w cmd 0x%x\n", cmd);
+ mh->mh_flags |= MHF_FWHANG;
+ return ETIMEDOUT;
+ }
+
+ bus_dmamap_sync(mh->mh_dmat, mh->mh_dmamap,
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+
+ return 0;
+}
+
+static int
+malo_hal_get_cal_table(struct malo_hal *mh, uint8_t annex, uint8_t index)
+{
+ struct malo_cmd_caltable *cmd;
+ int ret;
+
+ MALO_HAL_LOCK_ASSERT(mh);
+
+ _CMD_SETUP(cmd, struct malo_cmd_caltable, MALO_HOSTCMD_GET_CALTABLE);
+ cmd->annex = annex;
+ cmd->index = index;
+
+ ret = malo_hal_execute_cmd(mh, MALO_HOSTCMD_GET_CALTABLE);
+ if (ret == 0 && cmd->caltbl[0] != annex && annex != 0 && annex != 255)
+ ret = EIO;
+ return ret;
+}
+
+static int
+malo_hal_get_pwrcal_table(struct malo_hal *mh, struct malo_hal_caldata *cal)
+{
+ const uint8_t *data;
+ int len;
+
+ MALO_HAL_LOCK(mh);
+ /* NB: we hold the lock so it's ok to use cmdbuf */
+ data = ((const struct malo_cmd_caltable *) mh->mh_cmdbuf)->caltbl;
+ if (malo_hal_get_cal_table(mh, 33, 0) == 0) {
+ len = (data[2] | (data[3] << 8)) - 12;
+ /* XXX validate len */
+ memcpy(cal->pt_ratetable_20m, &data[12], len);
+ }
+ mh->mh_flags |= MHF_CALDATA;
+ MALO_HAL_UNLOCK(mh);
+
+ return 0;
+}
+
+/*
+ * Reset internal state after a firmware download.
+ */
+static int
+malo_hal_resetstate(struct malo_hal *mh)
+{
+ /*
+ * Fetch cal data for later use.
+ * XXX may want to fetch other stuff too.
+ */
+ if ((mh->mh_flags & MHF_CALDATA) == 0)
+ malo_hal_get_pwrcal_table(mh, &mh->mh_caldata);
+ return 0;
+}
+
+static void
+malo_hal_fw_reset(struct malo_hal *mh)
+{
+
+ if (malo_hal_read4(mh, MALO_REG_INT_CODE) == 0xffffffff) {
+ device_printf(mh->mh_dev, "%s: device not present!\n",
+ __func__);
+ return;
+ }
+
+ malo_hal_write4(mh, MALO_REG_H2A_INTERRUPT_EVENTS, MALO_ISR_RESET);
+ mh->mh_flags &= ~MHF_FWHANG;
+}
+
+static void
+malo_hal_trigger_pcicmd(struct malo_hal *mh)
+{
+ uint32_t dummy;
+
+ bus_dmamap_sync(mh->mh_dmat, mh->mh_dmamap, BUS_DMASYNC_PREWRITE);
+
+ malo_hal_write4(mh, MALO_REG_GEN_PTR, mh->mh_cmdaddr);
+ dummy = malo_hal_read4(mh, MALO_REG_INT_CODE);
+
+ malo_hal_write4(mh, MALO_REG_INT_CODE, 0x00);
+ dummy = malo_hal_read4(mh, MALO_REG_INT_CODE);
+
+ malo_hal_write4(mh, MALO_REG_H2A_INTERRUPT_EVENTS,
+ MALO_H2ARIC_BIT_DOOR_BELL);
+ dummy = malo_hal_read4(mh, MALO_REG_INT_CODE);
+}
+
+static int
+malo_hal_waitfor(struct malo_hal *mh, uint32_t val)
+{
+ int i;
+
+ for (i = 0; i < MALO_FW_MAX_NUM_CHECKS; i++) {
+ DELAY(MALO_FW_CHECK_USECS);
+ if (malo_hal_read4(mh, MALO_REG_INT_CODE) == val)
+ return 0;
+ }
+
+ return -1;
+}
+
+/*
+ * Firmware block xmit when talking to the boot-rom.
+ */
+static int
+malo_hal_send_helper(struct malo_hal *mh, int bsize,
+ const void *data, size_t dsize, int waitfor)
+{
+ mh->mh_cmdbuf[0] = htole16(MALO_HOSTCMD_CODE_DNLD);
+ mh->mh_cmdbuf[1] = htole16(bsize);
+ memcpy(&mh->mh_cmdbuf[4], data , dsize);
+
+ malo_hal_trigger_pcicmd(mh);
+
+ if (waitfor == MALO_NOWAIT)
+ goto pass;
+
+ /* XXX 2000 vs 200 */
+ if (malo_hal_waitfor(mh, MALO_INT_CODE_CMD_FINISHED) != 0) {
+ device_printf(mh->mh_dev,
+ "%s: timeout waiting for CMD_FINISHED, INT_CODE 0x%x\n",
+ __func__, malo_hal_read4(mh, MALO_REG_INT_CODE));
+
+ return ETIMEDOUT;
+ }
+
+pass:
+ malo_hal_write4(mh, MALO_REG_INT_CODE, 0);
+
+ return (0);
+}
+
+static int
+malo_hal_fwload_helper(struct malo_hal *mh, char *helper)
+{
+ const struct firmware *fw;
+ int error;
+
+ fw = firmware_get(helper);
+ if (fw == NULL) {
+ device_printf(mh->mh_dev, "could not read microcode %s!\n",
+ helper);
+ return (EIO);
+ }
+
+ device_printf(mh->mh_dev, "load %s firmware image (%u bytes)\n",
+ helper, fw->datasize);
+
+ error = malo_hal_send_helper(mh, fw->datasize, fw->data, fw->datasize,
+ MALO_WAITOK);
+ if (error != 0)
+ goto fail;
+
+ /* tell the card we're done and... */
+ error = malo_hal_send_helper(mh, 0, NULL, 0, MALO_NOWAIT);
+
+fail:
+ firmware_put(fw, FIRMWARE_UNLOAD);
+
+ return (error);
+}
+
+/*
+ * Firmware block xmit when talking to the 1st-stage loader.
+ */
+static int
+malo_hal_send_main(struct malo_hal *mh, const void *data, size_t dsize,
+ uint16_t seqnum, int waitfor)
+{
+ mh->mh_cmdbuf[0] = htole16(MALO_HOSTCMD_CODE_DNLD);
+ mh->mh_cmdbuf[1] = htole16(dsize);
+ mh->mh_cmdbuf[2] = htole16(seqnum);
+ mh->mh_cmdbuf[3] = 0;
+ memcpy(&mh->mh_cmdbuf[4], data, dsize);
+
+ malo_hal_trigger_pcicmd(mh);
+
+ if (waitfor == MALO_NOWAIT)
+ goto pass;
+
+ if (malo_hal_waitfor(mh, MALO_INT_CODE_CMD_FINISHED) != 0) {
+ device_printf(mh->mh_dev,
+ "%s: timeout waiting for CMD_FINISHED, INT_CODE 0x%x\n",
+ __func__, malo_hal_read4(mh, MALO_REG_INT_CODE));
+
+ return ETIMEDOUT;
+ }
+
+pass:
+ malo_hal_write4(mh, MALO_REG_INT_CODE, 0);
+
+ return 0;
+}
+
+static int
+malo_hal_fwload_main(struct malo_hal *mh, char *firmware)
+{
+ const struct firmware *fw;
+ const uint8_t *fp;
+ int error;
+ size_t count;
+ uint16_t seqnum;
+ uint32_t blocksize;
+
+ error = 0;
+
+ fw = firmware_get(firmware);
+ if (fw == NULL) {
+ device_printf(mh->mh_dev, "could not read firmware %s!\n",
+ firmware);
+ return (EIO);
+ }
+
+ device_printf(mh->mh_dev, "load %s firmware image (%u bytes)\n",
+ firmware, fw->datasize);
+
+ seqnum = 1;
+ for (count = 0; count < fw->datasize; count += blocksize) {
+ blocksize = MIN(256, fw->datasize - count);
+ fp = (const uint8_t *)fw->data + count;
+
+ error = malo_hal_send_main(mh, fp, blocksize, seqnum++,
+ MALO_NOWAIT);
+ if (error != 0)
+ goto fail;
+ DELAY(500);
+ }
+
+ /*
+ * send a command with size 0 to tell that the firmware has been
+ * uploaded
+ */
+ error = malo_hal_send_main(mh, NULL, 0, seqnum++, MALO_NOWAIT);
+ DELAY(100);
+
+fail:
+ firmware_put(fw, FIRMWARE_UNLOAD);
+
+ return (error);
+}
+
+int
+malo_hal_fwload(struct malo_hal *mh, char *helper, char *firmware)
+{
+ int error, i;
+ uint32_t fwreadysig, opmode;
+
+ /*
+ * NB: now malo(4) supports only STA mode. It will be better if it
+ * supports AP mode.
+ */
+ fwreadysig = MALO_HOSTCMD_STA_FWRDY_SIGNATURE;
+ opmode = MALO_HOSTCMD_STA_MODE;
+
+ malo_hal_fw_reset(mh);
+
+ malo_hal_write4(mh, MALO_REG_A2H_INTERRUPT_CLEAR_SEL,
+ MALO_A2HRIC_BIT_MASK);
+ malo_hal_write4(mh, MALO_REG_A2H_INTERRUPT_CAUSE, 0x00);
+ malo_hal_write4(mh, MALO_REG_A2H_INTERRUPT_MASK, 0x00);
+ malo_hal_write4(mh, MALO_REG_A2H_INTERRUPT_STATUS_MASK,
+ MALO_A2HRIC_BIT_MASK);
+
+ error = malo_hal_fwload_helper(mh, helper);
+ if (error != 0) {
+ device_printf(mh->mh_dev, "failed to load bootrom loader.\n");
+ goto fail;
+ }
+
+ DELAY(200 * MALO_FW_CHECK_USECS);
+
+ error = malo_hal_fwload_main(mh, firmware);
+ if (error != 0) {
+ device_printf(mh->mh_dev, "failed to load firmware.\n");
+ goto fail;
+ }
+
+ /*
+ * Wait for firmware to startup; we monitor the INT_CODE register
+ * waiting for a signature to written back indicating it's ready to go.
+ */
+ mh->mh_cmdbuf[1] = 0;
+
+ if (opmode != MALO_HOSTCMD_STA_MODE)
+ malo_hal_trigger_pcicmd(mh);
+
+ for (i = 0; i < MALO_FW_MAX_NUM_CHECKS; i++) {
+ malo_hal_write4(mh, MALO_REG_GEN_PTR, opmode);
+ DELAY(MALO_FW_CHECK_USECS);
+ if (malo_hal_read4(mh, MALO_REG_INT_CODE) == fwreadysig) {
+ malo_hal_write4(mh, MALO_REG_INT_CODE, 0x00);
+ return malo_hal_resetstate(mh);
+ }
+ }
+
+ return ETIMEDOUT;
+fail:
+ malo_hal_fw_reset(mh);
+
+ return (error);
+}
+
+/*
+ * Return "hw specs". Note this must be the first cmd MUST be done after
+ * a firmware download or the f/w will lockup.
+ */
+int
+malo_hal_gethwspecs(struct malo_hal *mh, struct malo_hal_hwspec *hw)
+{
+ struct malo_cmd_get_hwspec *cmd;
+ int ret;
+
+ MALO_HAL_LOCK(mh);
+
+ _CMD_SETUP(cmd, struct malo_cmd_get_hwspec, MALO_HOSTCMD_GET_HW_SPEC);
+ memset(&cmd->permaddr[0], 0xff, IEEE80211_ADDR_LEN);
+ cmd->ul_fw_awakecookie = htole32((unsigned int)mh->mh_cmdaddr + 2048);
+
+ ret = malo_hal_execute_cmd(mh, MALO_HOSTCMD_GET_HW_SPEC);
+ if (ret == 0) {
+ IEEE80211_ADDR_COPY(hw->macaddr, cmd->permaddr);
+ hw->wcbbase[0] = le32toh(cmd->wcbbase0) & 0x0000ffff;
+ hw->wcbbase[1] = le32toh(cmd->wcbbase1) & 0x0000ffff;
+ hw->wcbbase[2] = le32toh(cmd->wcbbase2) & 0x0000ffff;
+ hw->wcbbase[3] = le32toh(cmd->wcbbase3) & 0x0000ffff;
+ hw->rxdesc_read = le32toh(cmd->rxpdrd_ptr)& 0x0000ffff;
+ hw->rxdesc_write = le32toh(cmd->rxpdwr_ptr)& 0x0000ffff;
+ hw->regioncode = le16toh(cmd->regioncode) & 0x00ff;
+ hw->fw_releasenum = le32toh(cmd->fw_releasenum);
+ hw->maxnum_wcb = le16toh(cmd->num_wcb);
+ hw->maxnum_mcaddr = le16toh(cmd->num_mcastaddr);
+ hw->num_antenna = le16toh(cmd->num_antenna);
+ hw->hwversion = cmd->version;
+ hw->hostinterface = cmd->hostif;
+ }
+
+ MALO_HAL_UNLOCK(mh);
+
+ return ret;
+}
+
+void
+malo_hal_detach(struct malo_hal *mh)
+{
+
+ bus_dmamem_free(mh->mh_dmat, mh->mh_cmdbuf, mh->mh_dmamap);
+ bus_dmamap_destroy(mh->mh_dmat, mh->mh_dmamap);
+ bus_dma_tag_destroy(mh->mh_dmat);
+ mtx_destroy(&mh->mh_mtx);
+ free(mh, M_DEVBUF);
+}
+
+/*
+ * Configure antenna use. Takes effect immediately.
+ *
+ * XXX tx antenna setting ignored
+ * XXX rx antenna setting should always be 3 (for now)
+ */
+int
+malo_hal_setantenna(struct malo_hal *mh, enum malo_hal_antenna dirset, int ant)
+{
+ struct malo_cmd_rf_antenna *cmd;
+ int ret;
+
+ if (!(dirset == MHA_ANTENNATYPE_RX || dirset == MHA_ANTENNATYPE_TX))
+ return EINVAL;
+
+ MALO_HAL_LOCK(mh);
+
+ _CMD_SETUP(cmd, struct malo_cmd_rf_antenna,
+ MALO_HOSTCMD_802_11_RF_ANTENNA);
+ cmd->action = htole16(dirset);
+ if (ant == 0) { /* default to all/both antennae */
+ /* XXX never reach now. */
+ ant = 3;
+ }
+ cmd->mode = htole16(ant);
+
+ ret = malo_hal_execute_cmd(mh, MALO_HOSTCMD_802_11_RF_ANTENNA);
+
+ MALO_HAL_UNLOCK(mh);
+
+ return ret;
+}
+
+/*
+ * Configure radio. Takes effect immediately.
+ *
+ * XXX preamble installed after set fixed rate cmd
+ */
+int
+malo_hal_setradio(struct malo_hal *mh, int onoff,
+ enum malo_hal_preamble preamble)
+{
+ struct malo_cmd_radio_control *cmd;
+ int ret;
+
+ MALO_HAL_LOCK(mh);
+
+ _CMD_SETUP(cmd, struct malo_cmd_radio_control,
+ MALO_HOSTCMD_802_11_RADIO_CONTROL);
+ cmd->action = htole16(MALO_HOSTCMD_ACT_GEN_SET);
+ if (onoff == 0)
+ cmd->control = 0;
+ else
+ cmd->control = htole16(preamble);
+ cmd->radio_on = htole16(onoff);
+
+ ret = malo_hal_execute_cmd(mh, MALO_HOSTCMD_802_11_RADIO_CONTROL);
+
+ MALO_HAL_UNLOCK(mh);
+
+ return ret;
+}
+
+/*
+ * Set the interrupt mask.
+ */
+void
+malo_hal_intrset(struct malo_hal *mh, uint32_t mask)
+{
+
+ malo_hal_write4(mh, MALO_REG_A2H_INTERRUPT_MASK, 0);
+ (void)malo_hal_read4(mh, MALO_REG_INT_CODE);
+
+ mh->mh_imask = mask;
+ malo_hal_write4(mh, MALO_REG_A2H_INTERRUPT_MASK, mask);
+ (void)malo_hal_read4(mh, MALO_REG_INT_CODE);
+}
+
+int
+malo_hal_setchannel(struct malo_hal *mh, const struct malo_hal_channel *chan)
+{
+ struct malo_cmd_fw_set_rf_channel *cmd;
+ int ret;
+
+ MALO_HAL_LOCK(mh);
+
+ _CMD_SETUP(cmd, struct malo_cmd_fw_set_rf_channel,
+ MALO_HOSTCMD_SET_RF_CHANNEL);
+ cmd->action = htole16(MALO_HOSTCMD_ACT_GEN_SET);
+ cmd->cur_channel = chan->channel;
+
+ ret = malo_hal_execute_cmd(mh, MALO_HOSTCMD_SET_RF_CHANNEL);
+
+ MALO_HAL_UNLOCK(mh);
+
+ return ret;
+}
+
+int
+malo_hal_settxpower(struct malo_hal *mh, const struct malo_hal_channel *c)
+{
+ struct malo_cmd_rf_tx_power *cmd;
+ const struct malo_hal_caldata *cal = &mh->mh_caldata;
+ uint8_t chan = c->channel;
+ uint16_t pow;
+ int i, idx, ret;
+
+ MALO_HAL_LOCK(mh);
+
+ _CMD_SETUP(cmd, struct malo_cmd_rf_tx_power,
+ MALO_HOSTCMD_802_11_RF_TX_POWER);
+ cmd->action = htole16(MALO_HOSTCMD_ACT_GEN_SET_LIST);
+ for (i = 0; i < 4; i++) {
+ idx = (chan - 1) * 4 + i;
+ pow = cal->pt_ratetable_20m[idx];
+ cmd->power_levellist[i] = htole16(pow);
+ }
+ ret = malo_hal_execute_cmd(mh, MALO_HOSTCMD_802_11_RF_TX_POWER);
+
+ MALO_HAL_UNLOCK(mh);
+
+ return ret;
+}
+
+int
+malo_hal_setpromisc(struct malo_hal *mh, int enable)
+{
+ /* XXX need host cmd */
+ return 0;
+}
+
+int
+malo_hal_setassocid(struct malo_hal *mh,
+ const uint8_t bssid[IEEE80211_ADDR_LEN], uint16_t associd)
+{
+ struct malo_cmd_fw_set_aid *cmd;
+ int ret;
+
+ MALO_HAL_LOCK(mh);
+
+ _CMD_SETUP(cmd, struct malo_cmd_fw_set_aid,
+ MALO_HOSTCMD_SET_AID);
+ cmd->cmdhdr.seqnum = 1;
+ cmd->associd = htole16(associd);
+ IEEE80211_ADDR_COPY(&cmd->macaddr[0], bssid);
+
+ ret = malo_hal_execute_cmd(mh, MALO_HOSTCMD_SET_AID);
+ MALO_HAL_UNLOCK(mh);
+ return ret;
+}
+
+/*
+ * Kick the firmware to tell it there are new tx descriptors
+ * for processing. The driver says what h/w q has work in
+ * case the f/w ever gets smarter.
+ */
+void
+malo_hal_txstart(struct malo_hal *mh, int qnum)
+{
+ bus_space_write_4(mh->mh_iot, mh->mh_ioh,
+ MALO_REG_H2A_INTERRUPT_EVENTS, MALO_H2ARIC_BIT_PPA_READY);
+ (void) bus_space_read_4(mh->mh_iot, mh->mh_ioh, MALO_REG_INT_CODE);
+}
+
+/*
+ * Return the current ISR setting and clear the cause.
+ */
+void
+malo_hal_getisr(struct malo_hal *mh, uint32_t *status)
+{
+ uint32_t cause;
+
+ cause = bus_space_read_4(mh->mh_iot, mh->mh_ioh,
+ MALO_REG_A2H_INTERRUPT_CAUSE);
+ if (cause == 0xffffffff) { /* card removed */
+ cause = 0;
+ } else if (cause != 0) {
+ /* clear cause bits */
+ bus_space_write_4(mh->mh_iot, mh->mh_ioh,
+ MALO_REG_A2H_INTERRUPT_CAUSE, cause &~ mh->mh_imask);
+ (void) bus_space_read_4(mh->mh_iot, mh->mh_ioh,
+ MALO_REG_INT_CODE);
+ cause &= mh->mh_imask;
+ }
+
+ *status = cause;
+}
+
+/*
+ * Callback from the driver on a cmd done interrupt. Nothing to do right
+ * now as we spin waiting for cmd completion.
+ */
+void
+malo_hal_cmddone(struct malo_hal *mh)
+{
+ /* NB : do nothing. */
+}
+
+int
+malo_hal_prescan(struct malo_hal *mh)
+{
+ struct malo_cmd_prescan *cmd;
+ int ret;
+
+ MALO_HAL_LOCK(mh);
+
+ _CMD_SETUP(cmd, struct malo_cmd_prescan, MALO_HOSTCMD_SET_PRE_SCAN);
+ cmd->cmdhdr.seqnum = 1;
+
+ ret = malo_hal_execute_cmd(mh, MALO_HOSTCMD_SET_PRE_SCAN);
+
+ MALO_HAL_UNLOCK(mh);
+
+ return ret;
+}
+
+int
+malo_hal_postscan(struct malo_hal *mh, uint8_t *macaddr, uint8_t ibsson)
+{
+ struct malo_cmd_postscan *cmd;
+ int ret;
+
+ MALO_HAL_LOCK(mh);
+
+ _CMD_SETUP(cmd, struct malo_cmd_postscan, MALO_HOSTCMD_SET_POST_SCAN);
+ cmd->cmdhdr.seqnum = 1;
+ cmd->isibss = htole32(ibsson);
+ IEEE80211_ADDR_COPY(&cmd->bssid[0], macaddr);
+
+ ret = malo_hal_execute_cmd(mh, MALO_HOSTCMD_SET_POST_SCAN);
+
+ MALO_HAL_UNLOCK(mh);
+
+ return ret;
+}
+
+int
+malo_hal_set_slot(struct malo_hal *mh, int is_short)
+{
+ int ret;
+ struct malo_cmd_fw_setslot *cmd;
+
+ MALO_HAL_LOCK(mh);
+
+ _CMD_SETUP(cmd, struct malo_cmd_fw_setslot, MALO_HOSTCMD_SET_SLOT);
+ cmd->action = htole16(MALO_HOSTCMD_ACT_GEN_SET);
+ cmd->slot = (is_short == 1 ? 1 : 0);
+
+ ret = malo_hal_execute_cmd(mh, MALO_HOSTCMD_SET_SLOT);
+
+ MALO_HAL_UNLOCK(mh);
+
+ return ret;
+}
+
+int
+malo_hal_set_rate(struct malo_hal *mh, uint16_t curmode, uint8_t rate)
+{
+ int i, ret;
+ struct malo_cmd_set_rate *cmd;
+
+ MALO_HAL_LOCK(mh);
+
+ _CMD_SETUP(cmd, struct malo_cmd_set_rate, MALO_HOSTCMD_SET_RATE);
+ cmd->aprates[0] = 2;
+ cmd->aprates[1] = 4;
+ cmd->aprates[2] = 11;
+ cmd->aprates[3] = 22;
+ if (curmode == IEEE80211_MODE_11G) {
+ cmd->aprates[4] = 0; /* XXX reserved? */
+ cmd->aprates[5] = 12;
+ cmd->aprates[6] = 18;
+ cmd->aprates[7] = 24;
+ cmd->aprates[8] = 36;
+ cmd->aprates[9] = 48;
+ cmd->aprates[10] = 72;
+ cmd->aprates[11] = 96;
+ cmd->aprates[12] = 108;
+ }
+
+ if (rate != 0) {
+ /* fixed rate */
+ for (i = 0; i < 13; i++) {
+ if (cmd->aprates[i] == rate) {
+ cmd->rateindex = i;
+ cmd->dataratetype = 1;
+ break;
+ }
+ }
+ }
+
+ ret = malo_hal_execute_cmd(mh, MALO_HOSTCMD_SET_RATE);
+
+ MALO_HAL_UNLOCK(mh);
+
+ return ret;
+}
+
+int
+malo_hal_setmcast(struct malo_hal *mh, int nmc, const uint8_t macs[])
+{
+ struct malo_cmd_mcast *cmd;
+ int ret;
+
+ if (nmc > MALO_HAL_MCAST_MAX)
+ return EINVAL;
+
+ MALO_HAL_LOCK(mh);
+
+ _CMD_SETUP(cmd, struct malo_cmd_mcast, MALO_HOSTCMD_MAC_MULTICAST_ADR);
+ memcpy(cmd->maclist, macs, nmc * IEEE80211_ADDR_LEN);
+ cmd->numaddr = htole16(nmc);
+ cmd->action = htole16(0xffff);
+
+ ret = malo_hal_execute_cmd(mh, MALO_HOSTCMD_MAC_MULTICAST_ADR);
+
+ MALO_HAL_UNLOCK(mh);
+
+ return ret;
+}
diff --git a/sys/dev/malo/if_malohal.h b/sys/dev/malo/if_malohal.h
new file mode 100644
index 0000000..80c27ac
--- /dev/null
+++ b/sys/dev/malo/if_malohal.h
@@ -0,0 +1,234 @@
+/*-
+ * Copyright (c) 2007 Marvell Semiconductor, Inc.
+ * Copyright (c) 2007 Sam Leffler, Errno Consulting
+ * Copyright (c) 2008 Weongyo Jeong <weongyo@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ * redistribution must be conditioned upon including a substantially
+ * similar Disclaimer requirement for further binary redistribution.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DEV_MALOHAL_H
+#define _DEV_MALOHAL_H
+
+#define MALO_NUM_TX_QUEUES 1
+#define MALO_MAX_TXWCB_QUEUES MALO_NUM_TX_QUEUES
+
+/* size of f/w command buffer */
+#define MALO_CMDBUF_SIZE 0x4000
+
+#define MALO_FW_CHECK_USECS (5 * 1000) /* 5ms */
+#define MALO_FW_MAX_NUM_CHECKS 200
+
+/*
+ * Calibration data builtin to the firmware. The firmware image
+ * has a single set of calibration tables that we retrieve right
+ * after download. This can be overriden by the driver (e.g. for
+ * a different regdomain and/or tx power setup).
+ */
+struct malo_hal_caldata {
+ /* pt is short for `power target'. */
+#define MALO_PWTAGETRATETABLE20M (14 * 4)
+ uint8_t pt_ratetable_20m[MALO_PWTAGETRATETABLE20M];
+};
+
+/*
+ * Get Hardware/Firmware capabilities.
+ */
+struct malo_hal_hwspec {
+ uint8_t hwversion; /* version of the HW */
+ uint8_t hostinterface; /* host interface */
+ uint16_t maxnum_wcb; /* max # of WCB FW handles */
+ /* max # of mcast addresses FW handles*/
+ uint16_t maxnum_mcaddr;
+ uint16_t maxnum_tx_wcb; /* max # of tx descs per WCB */
+ /* MAC address programmed in HW */
+ uint8_t macaddr[6];
+ uint16_t regioncode; /* EEPROM region code */
+ uint16_t num_antenna; /* Number of antenna used */
+ uint32_t fw_releasenum; /* firmware release number */
+ uint32_t wcbbase0;
+ uint32_t rxdesc_read;
+ uint32_t rxdesc_write;
+ uint32_t ul_fw_awakecookie;
+ uint32_t wcbbase[4];
+};
+
+/*
+ * Supply tx/rx dma-related settings to the firmware.
+ */
+struct malo_hal_txrxdma {
+ uint32_t maxnum_wcb; /* max # of WCB FW handles */
+ uint32_t maxnum_txwcb; /* max # of tx descs per WCB */
+ uint32_t rxdesc_read;
+ uint32_t rxdesc_write;
+ uint32_t wcbbase[4];
+};
+
+/*
+ * Get Hardware Statistics.
+ *
+ * Items marked with ! are deprecated and not ever updated. In
+ * some cases this is because work has been moved to the host (e.g.
+ * rx defragmentation).
+ *
+ * XXX low/up cases.
+ */
+struct malo_hal_hwstats {
+ uint32_t TxRetrySuccesses; /* tx success w/ 1 retry */
+ uint32_t TxMultipleRetrySuccesses;/* tx success w/ >1 retry */
+ uint32_t TxFailures; /* tx fail due to no ACK */
+ uint32_t RTSSuccesses; /* CTS rx'd for RTS */
+ uint32_t RTSFailures; /* CTS not rx'd for RTS */
+ uint32_t AckFailures; /* same as TxFailures */
+ uint32_t RxDuplicateFrames; /* rx discard for dup seqno */
+ uint32_t FCSErrorCount; /* rx discard for bad FCS */
+ uint32_t TxWatchDogTimeouts; /* MAC tx hang (f/w recovery) */
+ uint32_t RxOverflows; /* no f/w buffer for rx data */
+ uint32_t RxFragErrors; /* !rx fail due to defrag */
+ uint32_t RxMemErrors; /* out of mem or desc corrupted
+ in some way */
+ uint32_t RxPointerErrors; /* MAC internal ptr problem */
+ uint32_t TxUnderflows; /* !tx underflow on dma */
+ uint32_t TxDone; /* MAC tx ops completed
+ (possibly w/ error) */
+ uint32_t TxDoneBufTryPut; /* ! */
+ uint32_t TxDoneBufPut; /* same as TxDone */
+ uint32_t Wait4TxBuf; /* !no f/w buf avail when
+ supplied a tx descriptor */
+ uint32_t TxAttempts; /* tx descriptors processed */
+ uint32_t TxSuccesses; /* tx attempts successful */
+ uint32_t TxFragments; /* tx with fragmentation */
+ uint32_t TxMulticasts; /* tx multicast frames */
+ uint32_t RxNonCtlPkts; /* rx non-control frames */
+ uint32_t RxMulticasts; /* rx multicast frames */
+ uint32_t RxUndecryptableFrames; /* rx failed due to crypto */
+ uint32_t RxICVErrors; /* rx failed due to ICV check */
+ uint32_t RxExcludedFrames; /* rx discarded, e.g. bssid */
+};
+
+/*
+ * Set Antenna Configuration (legacy operation).
+ *
+ * The RX antenna can be selected using the the bitmask
+ * ant (bit 0 = antenna 1, bit 1 = antenna 2, etc.)
+ * (diversity?XXX)
+ */
+enum malo_hal_antenna {
+ MHA_ANTENNATYPE_RX = 1,
+ MHA_ANTENNATYPE_TX = 2,
+};
+
+/*
+ * Set Radio Configuration.
+ *
+ * onoff != 0 turns radio on; otherwise off.
+ * if radio is enabled, the preamble is set too.
+ */
+enum malo_hal_preamble {
+ MHP_LONG_PREAMBLE = 1,
+ MHP_SHORT_PREAMBLE = 3,
+ MHP_AUTO_PREAMBLE = 5,
+};
+
+struct malo_hal_channel_flags {
+ uint32_t freqband : 6,
+#define MALO_FREQ_BAND_2DOT4GHZ 0x1
+ : 26; /* reserved */
+};
+
+struct malo_hal_channel {
+ uint32_t channel;
+ struct malo_hal_channel_flags flags;
+};
+
+struct malo_hal_txrate {
+ uint8_t mcastrate; /* rate for multicast frames */
+ uint8_t mgtrate; /* rate for management frames */
+ struct {
+ uint8_t trycount; /* try this many times */
+ uint8_t rate; /* use this tx rate */
+ } rateseries[4]; /* rate series */
+};
+
+struct malo_hal {
+ device_t mh_dev;
+
+ bus_space_handle_t mh_ioh; /* BAR 1 copied from softc */
+ bus_space_tag_t mh_iot;
+ uint32_t mh_imask; /* interrupt mask */
+ int mh_flags;
+#define MHF_CALDATA 0x0001 /* cal data retrieved */
+#define MHF_FWHANG 0x0002 /* fw appears hung */
+
+ char mh_mtxname[12];
+ struct mtx mh_mtx;
+ bus_dma_tag_t mh_dmat; /* bus DMA tag for cmd buffer */
+ bus_dmamap_t mh_dmamap; /* DMA map for cmd buffer */
+ uint16_t *mh_cmdbuf; /* f/w cmd buffer */
+ bus_addr_t mh_cmdaddr; /* physaddr of cmd buffer */
+
+ struct malo_hal_caldata mh_caldata;
+
+ int mh_debug;
+#define MALO_HAL_DEBUG_SENDCMD 0x00000001
+#define MALO_HAL_DEBUG_CMDDONE 0x00000002
+#define MALO_HAL_DEBUG_IGNHANG 0X00000004
+};
+
+#define MALO_HAL_LOCK(mh) mtx_lock(&mh->mh_mtx)
+#define MALO_HAL_LOCK_ASSERT(mh) mtx_assert(&mh->mh_mtx, MA_OWNED)
+#define MALO_HAL_UNLOCK(mh) mtx_unlock(&mh->mh_mtx)
+
+struct malo_hal *malo_hal_attach(device_t, uint16_t,
+ bus_space_handle_t, bus_space_tag_t,
+ bus_dma_tag_t);
+int malo_hal_fwload(struct malo_hal *, char *, char *);
+int malo_hal_gethwspecs(struct malo_hal *,
+ struct malo_hal_hwspec *);
+void malo_hal_detach(struct malo_hal *);
+void malo_hal_intrset(struct malo_hal *, uint32_t);
+int malo_hal_setantenna(struct malo_hal *,
+ enum malo_hal_antenna, int);
+int malo_hal_setradio(struct malo_hal *, int,
+ enum malo_hal_preamble);
+int malo_hal_setchannel(struct malo_hal *,
+ const struct malo_hal_channel *);
+int malo_hal_setmaxtxpwr(struct malo_hal *, uint16_t);
+int malo_hal_settxpower(struct malo_hal *, const struct malo_hal_channel *);
+int malo_hal_setpromisc(struct malo_hal *, int);
+int malo_hal_setassocid(struct malo_hal *,
+ const uint8_t[], uint16_t);
+void malo_hal_txstart(struct malo_hal *, int);
+void malo_hal_getisr(struct malo_hal *, uint32_t *);
+void malo_hal_cmddone(struct malo_hal *);
+int malo_hal_prescan(struct malo_hal *);
+int malo_hal_postscan(struct malo_hal *, uint8_t *, uint8_t);
+int malo_hal_set_slot(struct malo_hal *, int);
+int malo_hal_set_rate(struct malo_hal *, uint16_t, uint8_t);
+int malo_hal_setmcast(struct malo_hal *, int, const uint8_t[]);
+
+#endif
diff --git a/sys/dev/malo/if_maloioctl.h b/sys/dev/malo/if_maloioctl.h
new file mode 100644
index 0000000..0647b15
--- /dev/null
+++ b/sys/dev/malo/if_maloioctl.h
@@ -0,0 +1,114 @@
+/*-
+ * Copyright (c) 2007 Marvell Semiconductor, Inc.
+ * Copyright (c) 2007 Sam Leffler, Errno Consulting
+ * Copyright (c) 2008 Weongyo Jeong <weongyo@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ * redistribution must be conditioned upon including a substantially
+ * similar Disclaimer requirement for further binary redistribution.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Ioctl-related defintions for the Marvel Wireless LAN controller driver.
+ */
+#ifndef _DEV_MALO_MVIOCTL_H
+#define _DEV_MALO_MVIOCTL_H
+
+struct malo_stats {
+ struct malo_hal_hwstats hw_stats; /* XXX tied to h/w defs */
+ uint32_t mst_failure; /* generic hardware failure */
+ uint32_t mst_rx_badtkipicv;
+ uint32_t mst_tx_discard;
+ uint32_t mst_tx_qstop;
+ uint32_t mst_tx_encap;
+ uint32_t mst_tx_mgmt;
+ uint32_t mst_rx_nombuf;
+ uint32_t mst_rx_busdma;
+ uint32_t mst_rx_tooshort;
+ uint32_t mst_tx_busdma;
+ uint32_t mst_tx_linear;
+ uint32_t mst_tx_nombuf;
+ uint32_t mst_tx_nodata;
+ uint32_t mst_tx_shortpre;
+ uint32_t mst_tx_retries;
+ uint32_t mst_tx_mretries;
+ uint32_t mst_tx_linkerror;
+ uint32_t mst_tx_xretries;
+ uint32_t mst_tx_aging;
+ uint32_t mst_watchdog;
+ uint32_t mst_tx_packets;
+ uint32_t mst_rx_packets;
+ int8_t mst_rx_rssi;
+ int8_t mst_rx_noise;
+ uint8_t mst_tx_rate;
+ uint32_t mst_ant_tx[4];
+ uint32_t mst_ant_rx[4];
+};
+
+#define SIOCGMVSTATS _IOWR('i', 137, struct ifreq)
+
+/*
+ * Radio capture format.
+ */
+#define MALO_RX_RADIOTAP_PRESENT ( \
+ (1 << IEEE80211_RADIOTAP_FLAGS) | \
+ (1 << IEEE80211_RADIOTAP_RATE) | \
+ (1 << IEEE80211_RADIOTAP_CHANNEL) | \
+ (1 << IEEE80211_RADIOTAP_ANTENNA) | \
+ (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | \
+ (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) | \
+ 0)
+
+struct malo_rx_radiotap_header {
+ struct ieee80211_radiotap_header wr_ihdr;
+ u_int8_t wr_flags;
+ u_int8_t wr_rate;
+ u_int16_t wr_chan_freq;
+ u_int16_t wr_chan_flags;
+ int8_t wr_antsignal;
+ int8_t wr_antnoise;
+ u_int8_t wr_antenna;
+};
+
+#define MALO_TX_RADIOTAP_PRESENT ( \
+ (1 << IEEE80211_RADIOTAP_FLAGS) | \
+ (1 << IEEE80211_RADIOTAP_RATE) | \
+ (1 << IEEE80211_RADIOTAP_CHANNEL) | \
+ (1 << IEEE80211_RADIOTAP_DBM_TX_POWER) | \
+ (1 << IEEE80211_RADIOTAP_ANTENNA) | \
+ 0)
+
+struct malo_tx_radiotap_header {
+ struct ieee80211_radiotap_header wt_ihdr;
+ u_int8_t wt_flags;
+ u_int8_t wt_rate;
+ u_int16_t wt_chan_freq;
+ u_int16_t wt_chan_flags;
+ u_int8_t wt_txpower;
+ u_int8_t wt_antenna;
+};
+
+#endif /* _DEV_MALO_MVIOCTL_H */
diff --git a/sys/modules/malo/Makefile b/sys/modules/malo/Makefile
new file mode 100644
index 0000000..c0e88c5
--- /dev/null
+++ b/sys/modules/malo/Makefile
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../../dev/malo
+
+KMOD = if_malo
+SRCS = if_malo.c if_malohal.c if_malo_pci.c device_if.h bus_if.h pci_if.h
+
+.include <bsd.kmod.mk>
OpenPOWER on IntegriCloud