The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/mwl/mwlhal.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2007-2009 Sam Leffler, Errno Consulting
    5  * Copyright (c) 2007-2009 Marvell Semiconductor, Inc.
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer,
   13  *    without modification.
   14  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
   15  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
   16  *    redistribution must be conditioned upon including a substantially
   17  *    similar Disclaimer requirement for further binary redistribution.
   18  *
   19  * NO WARRANTY
   20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   22  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
   23  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
   24  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
   25  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
   28  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
   30  * THE POSSIBILITY OF SUCH DAMAGES.
   31  *
   32  * $FreeBSD$
   33  */
   34 
   35 #include <sys/param.h>
   36 #include <sys/systm.h> 
   37 #include <sys/sysctl.h>
   38 #include <sys/malloc.h>
   39 #include <sys/lock.h>
   40 #include <sys/mutex.h>
   41 #include <sys/kernel.h>
   42 #include <sys/errno.h>
   43 #include <sys/bus.h>
   44 #include <sys/endian.h>
   45 
   46 #include <sys/linker.h>
   47 #include <sys/firmware.h>
   48 
   49 #include <machine/bus.h>
   50 
   51 #include <dev/mwl/mwlhal.h>
   52 #include <dev/mwl/mwlreg.h>
   53 
   54 #include <sys/socket.h>
   55 #include <sys/sockio.h>
   56 #include <net/if.h>
   57 #include <dev/mwl/mwldiag.h>
   58 
   59 #define MWLHAL_DEBUG                    /* debug msgs */
   60 
   61 typedef enum {
   62     WL_ANTENNAMODE_RX = 0xffff,
   63     WL_ANTENNAMODE_TX = 2,
   64 } wlantennamode_e;
   65 
   66 typedef enum {
   67     WL_TX_POWERLEVEL_LOW = 5,
   68     WL_TX_POWERLEVEL_MEDIUM = 10,
   69     WL_TX_POWERLEVEL_HIGH = 15,
   70 } wltxpowerlevel_e;
   71 
   72 #define MWL_CMDBUF_SIZE 0x4000          /* size of f/w command buffer */
   73 #define MWL_BASTREAMS_MAX       7       /* max BA streams (NB: fw >3.3.5.9) */
   74 #define MWL_BAQID_MAX           8       /* max BA Q id's (NB: fw >3.3.5.9) */
   75 #define MWL_MBSS_AP_MAX         8       /* max ap vap's */
   76 #define MWL_MBSS_STA_MAX        24      /* max station/client vap's */
   77 #define MWL_MBSS_MAX    (MWL_MBSS_AP_MAX+MWL_MBSS_STA_MAX)
   78 
   79 /*
   80  * BA stream -> queue ID mapping
   81  *
   82  * The first 2 streams map to h/w; the remaining streams are
   83  * implemented in firmware.
   84  */
   85 static const int ba2qid[MWL_BASTREAMS_MAX] = {
   86         5, 6                            /* h/w supported */
   87 #if MWL_BASTREAMS_MAX == 7
   88         , 7, 0, 1, 2, 3                 /* f/w supported */
   89 #endif
   90 };
   91 static int qid2ba[MWL_BAQID_MAX];
   92 
   93 #define IEEE80211_ADDR_LEN      6       /* XXX */
   94 #define IEEE80211_ADDR_COPY(_dst, _src) \
   95         memcpy(_dst, _src, IEEE80211_ADDR_LEN)
   96 #define IEEE80211_ADDR_EQ(_dst, _src) \
   97         (memcmp(_dst, _src, IEEE80211_ADDR_LEN) == 0)
   98 
   99 #define _CMD_SETUP(pCmd, type, cmd) do {                                \
  100         pCmd = (type *)&mh->mh_cmdbuf[0];                               \
  101         memset(pCmd, 0, sizeof(type));                                  \
  102         pCmd->CmdHdr.Cmd = htole16(cmd);                                \
  103         pCmd->CmdHdr.Length = htole16(sizeof(type));                    \
  104 } while (0)
  105 
  106 #define _VCMD_SETUP(vap, pCmd, type, cmd) do {                          \
  107         _CMD_SETUP(pCmd, type, cmd);                                    \
  108         pCmd->CmdHdr.MacId = vap->macid;                                \
  109 } while (0)
  110 
  111 #define PWTAGETRATETABLE20M     14*4
  112 #define PWTAGETRATETABLE40M     9*4
  113 #define PWTAGETRATETABLE20M_5G  35*4
  114 #define PWTAGETRATETABLE40M_5G  16*4
  115 
  116 struct mwl_hal_bastream {
  117         MWL_HAL_BASTREAM public;        /* public state */
  118         uint8_t stream;                 /* stream # */
  119         uint8_t setup;                  /* f/w cmd sent */
  120         uint8_t ba_policy;              /* direct/delayed BA policy */
  121         uint8_t tid;
  122         uint8_t paraminfo;
  123         uint8_t macaddr[IEEE80211_ADDR_LEN];
  124 };
  125 
  126 struct mwl_hal_priv;
  127 
  128 struct mwl_hal_vap {
  129         struct mwl_hal_priv *mh;        /* back pointer */
  130         uint16_t bss_type;              /* f/w type */
  131         uint8_t vap_type;               /* MWL_HAL_BSSTYPE */
  132         uint8_t macid;                  /* for passing to f/w */
  133         uint8_t flags;
  134 #define MVF_RUNNING     0x01            /* BSS_START issued */
  135 #define MVF_STATION     0x02            /* sta db entry created */
  136         uint8_t mac[IEEE80211_ADDR_LEN];/* mac address */
  137 };
  138 #define MWLVAP(_vap)    ((_vap)->mh)
  139 
  140 /*
  141  * Per-device state.  We allocate a single cmd buffer for
  142  * submitting operations to the firmware.  Access to this
  143  * buffer (and the f/w) are single-threaded.  At present
  144  * we spin waiting for cmds to complete which is bad.  Not
  145  * sure if it's possible to submit multiple requests or
  146  * control when we get cmd done interrupts.  There's no
  147  * documentation and no example code to indicate what can
  148  * or cannot be done so all we can do right now is follow the
  149  * linux driver logic.  This falls apart when the f/w fails;
  150  * the system comes to a crawl as we spin waiting for operations
  151  * to finish.
  152  */
  153 struct mwl_hal_priv {
  154         struct mwl_hal  public;         /* public area */
  155         device_t        mh_dev;
  156         char            mh_mtxname[12];
  157         struct mtx      mh_mtx;
  158         bus_dma_tag_t   mh_dmat;        /* bus DMA tag for cmd buffer */
  159         bus_dma_segment_t mh_seg;       /* segment for cmd buffer */
  160         bus_dmamap_t    mh_dmamap;      /* DMA map for cmd buffer */
  161         uint16_t        *mh_cmdbuf;     /* f/w cmd buffer */
  162         bus_addr_t      mh_cmdaddr;     /* physaddr of cmd buffer */
  163         int             mh_flags;
  164 #define MHF_CALDATA     0x0001          /* cal data retrieved */
  165 #define MHF_FWHANG      0x0002          /* fw appears hung */
  166 #define MHF_MBSS        0x0004          /* mbss enabled */
  167         struct mwl_hal_vap mh_vaps[MWL_MBSS_MAX+1];
  168         int             mh_bastreams;   /* bit mask of available BA streams */
  169         int             mh_regioncode;  /* XXX last region code sent to fw */
  170         struct mwl_hal_bastream mh_streams[MWL_BASTREAMS_MAX];
  171         int             mh_debug;
  172         MWL_HAL_CHANNELINFO mh_20M;
  173         MWL_HAL_CHANNELINFO mh_40M;
  174         MWL_HAL_CHANNELINFO mh_20M_5G;
  175         MWL_HAL_CHANNELINFO mh_40M_5G;
  176         int             mh_SDRAMSIZE_Addr;
  177         uint32_t        mh_RTSSuccesses;/* cumulative stats for read-on-clear */
  178         uint32_t        mh_RTSFailures;
  179         uint32_t        mh_RxDuplicateFrames;
  180         uint32_t        mh_FCSErrorCount;
  181         MWL_DIAG_REVS   mh_revs;
  182 };
  183 #define MWLPRIV(_mh)    ((struct mwl_hal_priv *)(_mh))
  184 
  185 static int mwl_hal_setmac_locked(struct mwl_hal_vap *,
  186         const uint8_t addr[IEEE80211_ADDR_LEN]);
  187 static int mwlExecuteCmd(struct mwl_hal_priv *, unsigned short cmd);
  188 static int mwlGetPwrCalTable(struct mwl_hal_priv *);
  189 #ifdef MWLHAL_DEBUG
  190 static const char *mwlcmdname(int cmd);
  191 static void dumpresult(struct mwl_hal_priv *, int showresult);
  192 #endif /* MWLHAL_DEBUG */
  193 
  194 SYSCTL_DECL(_hw_mwl);
  195 static SYSCTL_NODE(_hw_mwl, OID_AUTO, hal, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
  196     "Marvell HAL parameters");
  197 
  198 static __inline void
  199 MWL_HAL_LOCK(struct mwl_hal_priv *mh)
  200 {
  201         mtx_lock(&mh->mh_mtx);
  202 }
  203 
  204 static __inline void
  205 MWL_HAL_LOCK_ASSERT(struct mwl_hal_priv *mh)
  206 {
  207         mtx_assert(&mh->mh_mtx, MA_OWNED);
  208 }
  209 
  210 static __inline void
  211 MWL_HAL_UNLOCK(struct mwl_hal_priv *mh)
  212 {
  213         mtx_unlock(&mh->mh_mtx);
  214 }
  215 
  216 static __inline uint32_t
  217 RD4(struct mwl_hal_priv *mh, bus_size_t off)
  218 {
  219         return bus_space_read_4(mh->public.mh_iot, mh->public.mh_ioh, off);
  220 }
  221 
  222 static __inline void
  223 WR4(struct mwl_hal_priv *mh, bus_size_t off, uint32_t val)
  224 {
  225         bus_space_write_4(mh->public.mh_iot, mh->public.mh_ioh, off, val);
  226 }
  227 
  228 static void
  229 mwl_hal_load_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
  230 {
  231         bus_addr_t *paddr = (bus_addr_t*) arg;
  232         KASSERT(error == 0, ("error %u on bus_dma callback", error));
  233         *paddr = segs->ds_addr;
  234 }
  235 
  236 /*
  237  * Setup for communication with the device.  We allocate
  238  * a command buffer and map it for bus dma use.  The pci
  239  * device id is used to identify whether the device has
  240  * SRAM on it (in which case f/w download must include a
  241  * memory controller reset).  All bus i/o operations happen
  242  * in BAR 1; the driver passes in the tag and handle we need.
  243  */
  244 struct mwl_hal *
  245 mwl_hal_attach(device_t dev, uint16_t devid,
  246     bus_space_handle_t ioh, bus_space_tag_t iot, bus_dma_tag_t tag)
  247 {
  248         struct mwl_hal_priv *mh;
  249         struct mwl_hal_vap *hvap;
  250         int error, i;
  251 
  252         mh = malloc(sizeof(struct mwl_hal_priv), M_DEVBUF, M_NOWAIT | M_ZERO);
  253         if (mh == NULL)
  254                 return NULL;
  255         mh->mh_dev = dev;
  256         mh->public.mh_ioh = ioh;
  257         mh->public.mh_iot = iot;
  258         for (i = 0; i < MWL_BASTREAMS_MAX; i++) {
  259                 mh->mh_streams[i].public.txq = ba2qid[i];
  260                 mh->mh_streams[i].stream = i;
  261                 /* construct back-mapping while we're at it */
  262                 if (mh->mh_streams[i].public.txq < MWL_BAQID_MAX)
  263                         qid2ba[mh->mh_streams[i].public.txq] = i;
  264                 else
  265                         device_printf(dev, "unexpected BA tx qid %d for "
  266                             "stream %d\n", mh->mh_streams[i].public.txq, i);
  267         }
  268         /* setup constant portion of vap state */
  269         /* XXX should get max ap/client vap's from f/w */
  270         i = 0;
  271         hvap = &mh->mh_vaps[i];
  272         hvap->vap_type = MWL_HAL_AP;
  273         hvap->bss_type = htole16(WL_MAC_TYPE_PRIMARY_AP);
  274         hvap->macid = 0;
  275         for (i++; i < MWL_MBSS_AP_MAX; i++) {
  276                 hvap = &mh->mh_vaps[i];
  277                 hvap->vap_type = MWL_HAL_AP;
  278                 hvap->bss_type = htole16(WL_MAC_TYPE_SECONDARY_AP);
  279                 hvap->macid = i;
  280         }
  281         hvap = &mh->mh_vaps[i];
  282         hvap->vap_type = MWL_HAL_STA;
  283         hvap->bss_type = htole16(WL_MAC_TYPE_PRIMARY_CLIENT);
  284         hvap->macid = i;
  285         for (i++; i < MWL_MBSS_MAX; i++) {
  286                 hvap = &mh->mh_vaps[i];
  287                 hvap->vap_type = MWL_HAL_STA;
  288                 hvap->bss_type = htole16(WL_MAC_TYPE_SECONDARY_CLIENT);
  289                 hvap->macid = i;
  290         }
  291         mh->mh_revs.mh_devid = devid;
  292         snprintf(mh->mh_mtxname, sizeof(mh->mh_mtxname),
  293             "%s_hal", device_get_nameunit(dev));
  294         mtx_init(&mh->mh_mtx, mh->mh_mtxname, NULL, MTX_DEF);
  295 
  296         /*
  297          * Allocate the command buffer and map into the address
  298          * space of the h/w.  We request "coherent" memory which
  299          * will be uncached on some architectures.
  300          */
  301         error = bus_dma_tag_create(tag,         /* parent */
  302                        PAGE_SIZE, 0,            /* alignment, bounds */
  303                        BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
  304                        BUS_SPACE_MAXADDR,       /* highaddr */
  305                        NULL, NULL,              /* filter, filterarg */
  306                        MWL_CMDBUF_SIZE,         /* maxsize */
  307                        1,                       /* nsegments */
  308                        MWL_CMDBUF_SIZE,         /* maxsegsize */
  309                        BUS_DMA_ALLOCNOW,        /* flags */
  310                        NULL,                    /* lockfunc */
  311                        NULL,                    /* lockarg */
  312                        &mh->mh_dmat);
  313         if (error != 0) {
  314                 device_printf(dev, "unable to allocate memory for cmd tag, "
  315                         "error %u\n", error);
  316                 goto fail0;
  317         }
  318 
  319         /* allocate descriptors */
  320         error = bus_dmamem_alloc(mh->mh_dmat, (void**) &mh->mh_cmdbuf,
  321                                  BUS_DMA_NOWAIT | BUS_DMA_COHERENT, 
  322                                  &mh->mh_dmamap);
  323         if (error != 0) {
  324                 device_printf(dev, "unable to allocate memory for cmd buffer, "
  325                         "error %u\n", error);
  326                 goto fail1;
  327         }
  328 
  329         error = bus_dmamap_load(mh->mh_dmat, mh->mh_dmamap,
  330                                 mh->mh_cmdbuf, MWL_CMDBUF_SIZE,
  331                                 mwl_hal_load_cb, &mh->mh_cmdaddr,
  332                                 BUS_DMA_NOWAIT);
  333         if (error != 0) {
  334                 device_printf(dev, "unable to load cmd buffer, error %u\n",
  335                         error);
  336                 goto fail2;
  337         }
  338 
  339         /*
  340          * Some cards have SDRAM.  When loading firmware we need
  341          * to reset the SDRAM controller prior to doing this.
  342          * When the SDRAMSIZE is non-zero we do that work in
  343          * mwl_hal_fwload.
  344          */
  345         switch (devid) {
  346         case 0x2a02:            /* CB82 */
  347         case 0x2a03:            /* CB85 */
  348         case 0x2a08:            /* MC85_B1 */
  349         case 0x2a0b:            /* CB85AP */
  350         case 0x2a24:
  351                 mh->mh_SDRAMSIZE_Addr = 0x40fe70b7;     /* 8M SDRAM */
  352                 break;
  353         case 0x2a04:            /* MC85 */
  354                 mh->mh_SDRAMSIZE_Addr = 0x40fc70b7;     /* 16M SDRAM */
  355                 break;
  356         default:
  357                 break;
  358         }
  359         return &mh->public;
  360 fail2:
  361         bus_dmamem_free(mh->mh_dmat, mh->mh_cmdbuf, mh->mh_dmamap);
  362 fail1:
  363         bus_dma_tag_destroy(mh->mh_dmat);
  364 fail0:
  365         mtx_destroy(&mh->mh_mtx);
  366         free(mh, M_DEVBUF);
  367         return NULL;
  368 }
  369 
  370 void
  371 mwl_hal_detach(struct mwl_hal *mh0)
  372 {
  373         struct mwl_hal_priv *mh = MWLPRIV(mh0);
  374 
  375         bus_dmamem_free(mh->mh_dmat, mh->mh_cmdbuf, mh->mh_dmamap);
  376         bus_dma_tag_destroy(mh->mh_dmat);
  377         mtx_destroy(&mh->mh_mtx);
  378         free(mh, M_DEVBUF);
  379 }
  380 
  381 /*
  382  * Reset internal state after a firmware download.
  383  */
  384 static int
  385 mwlResetHalState(struct mwl_hal_priv *mh)
  386 {
  387         int i;
  388 
  389         /* XXX get from f/w */
  390         mh->mh_bastreams = (1<<MWL_BASTREAMS_MAX)-1;
  391         for (i = 0; i < MWL_MBSS_MAX; i++)
  392                 mh->mh_vaps[i].mh = NULL;
  393         /*
  394          * Clear cumulative stats.
  395          */
  396         mh->mh_RTSSuccesses = 0;
  397         mh->mh_RTSFailures = 0;
  398         mh->mh_RxDuplicateFrames = 0;
  399         mh->mh_FCSErrorCount = 0;
  400         /*
  401          * Fetch cal data for later use.
  402          * XXX may want to fetch other stuff too.
  403          */
  404         /* XXX check return */
  405         if ((mh->mh_flags & MHF_CALDATA) == 0)
  406                 mwlGetPwrCalTable(mh);
  407         return 0;
  408 }
  409 
  410 struct mwl_hal_vap *
  411 mwl_hal_newvap(struct mwl_hal *mh0, MWL_HAL_BSSTYPE type,
  412         const uint8_t mac[IEEE80211_ADDR_LEN])
  413 {
  414         struct mwl_hal_priv *mh = MWLPRIV(mh0);
  415         struct mwl_hal_vap *vap;
  416         int i;
  417 
  418         MWL_HAL_LOCK(mh);
  419         /* NB: could optimize but not worth it w/ max 32 bss */
  420         for (i = 0; i < MWL_MBSS_MAX; i++) {
  421                 vap = &mh->mh_vaps[i];
  422                 if (vap->vap_type == type && vap->mh == NULL) {
  423                         vap->mh = mh;
  424                         mwl_hal_setmac_locked(vap, mac);
  425                         break;
  426                 }
  427         }
  428         MWL_HAL_UNLOCK(mh);
  429         return (i < MWL_MBSS_MAX) ? vap : NULL;
  430 }
  431 
  432 void
  433 mwl_hal_delvap(struct mwl_hal_vap *vap)
  434 {
  435         /* NB: locking not needed for single write */
  436         vap->mh = NULL;
  437 }
  438 
  439 /*
  440  * Manipulate the debug mask.  Note debug
  441  * msgs are only provided when this code is
  442  * compiled with MWLHAL_DEBUG defined.
  443  */
  444 
  445 void
  446 mwl_hal_setdebug(struct mwl_hal *mh, int debug)
  447 {
  448         MWLPRIV(mh)->mh_debug = debug;
  449 }
  450 
  451 int
  452 mwl_hal_getdebug(struct mwl_hal *mh)
  453 {
  454         return MWLPRIV(mh)->mh_debug;
  455 }
  456 
  457 void
  458 mwl_hal_setbastreams(struct mwl_hal *mh, int mask)
  459 {
  460         MWLPRIV(mh)->mh_bastreams = mask & ((1<<MWL_BASTREAMS_MAX)-1);
  461 }
  462 
  463 int
  464 mwl_hal_getbastreams(struct mwl_hal *mh)
  465 {
  466         return MWLPRIV(mh)->mh_bastreams;
  467 }
  468 
  469 int
  470 mwl_hal_ismbsscapable(struct mwl_hal *mh)
  471 {
  472         return (MWLPRIV(mh)->mh_flags & MHF_MBSS) != 0;
  473 }
  474 
  475 #if 0
  476 /* XXX inlined */
  477 /*
  478  * Return the current ISR setting and clear the cause.
  479  * XXX maybe make inline
  480  */
  481 void
  482 mwl_hal_getisr(struct mwl_hal *mh0, uint32_t *status)
  483 {
  484         struct mwl_hal_priv *mh = MWLPRIV(mh0);
  485         uint32_t cause;
  486 
  487         cause = RD4(mh, MACREG_REG_A2H_INTERRUPT_CAUSE);
  488         if (cause == 0xffffffff) {      /* card removed */
  489 device_printf(mh->mh_dev, "%s: cause 0x%x\n", __func__, cause);
  490                 cause = 0;
  491         } else if (cause != 0) {
  492                 /* clear cause bits */
  493                 WR4(mh, MACREG_REG_A2H_INTERRUPT_CAUSE,
  494                     cause &~ mh->public.mh_imask);
  495                 RD4(mh, MACREG_REG_INT_CODE);   /* XXX flush write? */
  496         }
  497         *status = cause;
  498 }
  499 #endif
  500 
  501 /*
  502  * Set the interrupt mask.
  503  */
  504 void
  505 mwl_hal_intrset(struct mwl_hal *mh0, uint32_t mask)
  506 {
  507         struct mwl_hal_priv *mh = MWLPRIV(mh0);
  508 
  509         WR4(mh, MACREG_REG_A2H_INTERRUPT_MASK, 0);
  510         RD4(mh, MACREG_REG_INT_CODE);
  511 
  512         mh->public.mh_imask = mask;
  513         WR4(mh, MACREG_REG_A2H_INTERRUPT_MASK, mask);
  514         RD4(mh, MACREG_REG_INT_CODE);
  515 }
  516 
  517 #if 0
  518 /* XXX inlined */
  519 /*
  520  * Kick the firmware to tell it there are new tx descriptors
  521  * for processing.  The driver says what h/w q has work in
  522  * case the f/w ever gets smarter.
  523  */
  524 void
  525 mwl_hal_txstart(struct mwl_hal *mh0, int qnum)
  526 {
  527         struct mwl_hal_priv *mh = MWLPRIV(mh0);
  528         uint32_t dummy;
  529 
  530         WR4(mh, MACREG_REG_H2A_INTERRUPT_EVENTS, MACREG_H2ARIC_BIT_PPA_READY);
  531         dummy = RD4(mh, MACREG_REG_INT_CODE);
  532 }
  533 #endif
  534 
  535 /*
  536  * Callback from the driver on a cmd done interrupt.
  537  * Nothing to do right now as we spin waiting for
  538  * cmd completion.
  539  */
  540 void
  541 mwl_hal_cmddone(struct mwl_hal *mh0)
  542 {
  543 #if 0
  544         struct mwl_hal_priv *mh = MWLPRIV(mh0);
  545 
  546         if (mh->mh_debug & MWL_HAL_DEBUG_CMDDONE) {
  547                 device_printf(mh->mh_dev, "cmd done interrupt:\n");
  548                 dumpresult(mh, 1);
  549         }
  550 #endif
  551 }
  552 
  553 /*
  554  * Return "hw specs".  Note this must be the first
  555  * cmd MUST be done after a firmware download or the
  556  * f/w will lockup.
  557  * XXX move into the hal so driver doesn't need to be responsible
  558  */
  559 int
  560 mwl_hal_gethwspecs(struct mwl_hal *mh0, struct mwl_hal_hwspec *hw)
  561 {
  562         struct mwl_hal_priv *mh = MWLPRIV(mh0);
  563         HostCmd_DS_GET_HW_SPEC *pCmd;
  564         int retval, minrev;
  565 
  566         MWL_HAL_LOCK(mh);
  567         _CMD_SETUP(pCmd, HostCmd_DS_GET_HW_SPEC, HostCmd_CMD_GET_HW_SPEC);
  568         memset(&pCmd->PermanentAddr[0], 0xff, IEEE80211_ADDR_LEN);
  569         pCmd->ulFwAwakeCookie = htole32((unsigned int)mh->mh_cmdaddr+2048);
  570 
  571         retval = mwlExecuteCmd(mh, HostCmd_CMD_GET_HW_SPEC);
  572         if (retval == 0) {
  573                 IEEE80211_ADDR_COPY(hw->macAddr, pCmd->PermanentAddr);
  574                 hw->wcbBase[0] = le32toh(pCmd->WcbBase0) & 0x0000ffff;
  575                 hw->wcbBase[1] = le32toh(pCmd->WcbBase1[0]) & 0x0000ffff;
  576                 hw->wcbBase[2] = le32toh(pCmd->WcbBase1[1]) & 0x0000ffff;
  577                 hw->wcbBase[3] = le32toh(pCmd->WcbBase1[2]) & 0x0000ffff;
  578                 hw->rxDescRead = le32toh(pCmd->RxPdRdPtr)& 0x0000ffff;
  579                 hw->rxDescWrite = le32toh(pCmd->RxPdWrPtr)& 0x0000ffff;
  580                 hw->regionCode = le16toh(pCmd->RegionCode) & 0x00ff;
  581                 hw->fwReleaseNumber = le32toh(pCmd->FWReleaseNumber);
  582                 hw->maxNumWCB = le16toh(pCmd->NumOfWCB);
  583                 hw->maxNumMCAddr = le16toh(pCmd->NumOfMCastAddr);
  584                 hw->numAntennas = le16toh(pCmd->NumberOfAntenna);
  585                 hw->hwVersion = pCmd->Version;
  586                 hw->hostInterface = pCmd->HostIf;
  587 
  588                 mh->mh_revs.mh_macRev = hw->hwVersion;          /* XXX */
  589                 mh->mh_revs.mh_phyRev = hw->hostInterface;      /* XXX */
  590 
  591                 minrev = ((hw->fwReleaseNumber) >> 16) & 0xff;
  592                 if (minrev >= 4) {
  593                         /* starting with 3.4.x.x s/w BA streams supported */
  594                         mh->mh_bastreams &= (1<<MWL_BASTREAMS_MAX)-1;
  595                 } else
  596                         mh->mh_bastreams &= (1<<2)-1;
  597         }
  598         MWL_HAL_UNLOCK(mh);
  599         return retval;
  600 }
  601 
  602 /*
  603  * Inform the f/w about location of the tx/rx dma data structures
  604  * and related state.  This cmd must be done immediately after a
  605  * mwl_hal_gethwspecs call or the f/w will lockup.
  606  */
  607 int
  608 mwl_hal_sethwdma(struct mwl_hal *mh0, const struct mwl_hal_txrxdma *dma)
  609 {
  610         struct mwl_hal_priv *mh = MWLPRIV(mh0);
  611         HostCmd_DS_SET_HW_SPEC *pCmd;
  612         int retval;
  613 
  614         MWL_HAL_LOCK(mh);
  615         _CMD_SETUP(pCmd, HostCmd_DS_SET_HW_SPEC, HostCmd_CMD_SET_HW_SPEC);
  616         pCmd->WcbBase[0] = htole32(dma->wcbBase[0]);
  617         pCmd->WcbBase[1] = htole32(dma->wcbBase[1]);
  618         pCmd->WcbBase[2] = htole32(dma->wcbBase[2]);
  619         pCmd->WcbBase[3] = htole32(dma->wcbBase[3]);
  620         pCmd->TxWcbNumPerQueue = htole32(dma->maxNumTxWcb);
  621         pCmd->NumTxQueues = htole32(dma->maxNumWCB);
  622         pCmd->TotalRxWcb = htole32(1);          /* XXX */
  623         pCmd->RxPdWrPtr = htole32(dma->rxDescRead);
  624         pCmd->Flags = htole32(SET_HW_SPEC_HOSTFORM_BEACON
  625 #ifdef MWL_HOST_PS_SUPPORT
  626                     | SET_HW_SPEC_HOST_POWERSAVE
  627 #endif
  628                     | SET_HW_SPEC_HOSTFORM_PROBERESP);
  629         /* disable multi-bss operation for A1-A4 parts */
  630         if (mh->mh_revs.mh_macRev < 5)
  631                 pCmd->Flags |= htole32(SET_HW_SPEC_DISABLEMBSS);
  632 
  633         retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_HW_SPEC);
  634         if (retval == 0) {
  635                 if (pCmd->Flags & htole32(SET_HW_SPEC_DISABLEMBSS))
  636                         mh->mh_flags &= ~MHF_MBSS;
  637                 else
  638                         mh->mh_flags |= MHF_MBSS;
  639         }
  640         MWL_HAL_UNLOCK(mh);
  641         return retval;
  642 }
  643 
  644 /*
  645  * Retrieve statistics from the f/w.
  646  * XXX should be in memory shared w/ driver
  647  */
  648 int
  649 mwl_hal_gethwstats(struct mwl_hal *mh0, struct mwl_hal_hwstats *stats)
  650 {
  651         struct mwl_hal_priv *mh = MWLPRIV(mh0);
  652         HostCmd_DS_802_11_GET_STAT *pCmd;
  653         int retval;
  654 
  655         MWL_HAL_LOCK(mh);
  656         _CMD_SETUP(pCmd, HostCmd_DS_802_11_GET_STAT,
  657                 HostCmd_CMD_802_11_GET_STAT);
  658 
  659         retval = mwlExecuteCmd(mh, HostCmd_CMD_802_11_GET_STAT);
  660         if (retval == 0) {
  661                 const uint32_t *sp = (const uint32_t *)&pCmd->TxRetrySuccesses;
  662                 uint32_t *dp = (uint32_t *)&stats->TxRetrySuccesses;
  663                 int i;
  664 
  665                 for (i = 0; i < sizeof(*stats)/sizeof(uint32_t); i++)
  666                         dp[i] = le32toh(sp[i]);
  667                 /*
  668                  * Update stats not returned by f/w but available
  669                  * through public registers.  Note these registers
  670                  * are "clear on read" so we maintain cumulative data.
  671                  * XXX register defines
  672                  */
  673                 mh->mh_RTSSuccesses += RD4(mh, 0xa834);
  674                 mh->mh_RTSFailures += RD4(mh, 0xa830);
  675                 mh->mh_RxDuplicateFrames += RD4(mh, 0xa84c);
  676                 mh->mh_FCSErrorCount += RD4(mh, 0xa840);
  677         }
  678         MWL_HAL_UNLOCK(mh);
  679 
  680         stats->RTSSuccesses = mh->mh_RTSSuccesses;
  681         stats->RTSFailures = mh->mh_RTSFailures;
  682         stats->RxDuplicateFrames = mh->mh_RxDuplicateFrames;
  683         stats->FCSErrorCount = mh->mh_FCSErrorCount;
  684         return retval;
  685 }
  686 
  687 /*
  688  * Set HT guard interval handling.
  689  * Takes effect immediately.
  690  */
  691 int
  692 mwl_hal_sethtgi(struct mwl_hal_vap *vap, int GIType)
  693 {
  694         struct mwl_hal_priv *mh = MWLVAP(vap);
  695         HostCmd_FW_HT_GUARD_INTERVAL *pCmd;
  696         int retval;
  697 
  698         MWL_HAL_LOCK(mh);
  699         _VCMD_SETUP(vap, pCmd, HostCmd_FW_HT_GUARD_INTERVAL,
  700                 HostCmd_CMD_HT_GUARD_INTERVAL);
  701         pCmd->Action = htole32(HostCmd_ACT_GEN_SET);
  702 
  703         if (GIType == 0) {
  704                 pCmd->GIType = htole32(GI_TYPE_LONG);
  705         } else if (GIType == 1) {
  706                 pCmd->GIType = htole32(GI_TYPE_LONG | GI_TYPE_SHORT);
  707         } else {
  708                 pCmd->GIType = htole32(GI_TYPE_LONG);
  709         }
  710 
  711         retval = mwlExecuteCmd(mh, HostCmd_CMD_HT_GUARD_INTERVAL);
  712         MWL_HAL_UNLOCK(mh);
  713         return retval;
  714 }
  715 
  716 /*
  717  * Configure radio.
  718  * Takes effect immediately.
  719  * XXX preamble installed after set fixed rate cmd
  720  */
  721 int
  722 mwl_hal_setradio(struct mwl_hal *mh0, int onoff, MWL_HAL_PREAMBLE preamble)
  723 {
  724         struct mwl_hal_priv *mh = MWLPRIV(mh0);
  725         HostCmd_DS_802_11_RADIO_CONTROL *pCmd;
  726         int retval;
  727 
  728         MWL_HAL_LOCK(mh);
  729         _CMD_SETUP(pCmd, HostCmd_DS_802_11_RADIO_CONTROL,
  730                 HostCmd_CMD_802_11_RADIO_CONTROL);
  731         pCmd->Action = htole16(HostCmd_ACT_GEN_SET);
  732         if (onoff == 0)
  733                 pCmd->Control = 0;
  734         else
  735                 pCmd->Control = htole16(preamble);
  736         pCmd->RadioOn = htole16(onoff);
  737 
  738         retval = mwlExecuteCmd(mh, HostCmd_CMD_802_11_RADIO_CONTROL);
  739         MWL_HAL_UNLOCK(mh);
  740         return retval;
  741 }
  742 
  743 /*
  744  * Configure antenna use.
  745  * Takes effect immediately.
  746  * XXX tx antenna setting ignored
  747  * XXX rx antenna setting should always be 3 (for now)
  748  */
  749 int
  750 mwl_hal_setantenna(struct mwl_hal *mh0, MWL_HAL_ANTENNA dirSet, int ant)
  751 {
  752         struct mwl_hal_priv *mh = MWLPRIV(mh0);
  753         HostCmd_DS_802_11_RF_ANTENNA *pCmd;
  754         int retval;
  755 
  756         if (!(dirSet == WL_ANTENNATYPE_RX || dirSet == WL_ANTENNATYPE_TX))
  757                 return EINVAL;
  758 
  759         MWL_HAL_LOCK(mh);
  760         _CMD_SETUP(pCmd, HostCmd_DS_802_11_RF_ANTENNA,
  761                 HostCmd_CMD_802_11_RF_ANTENNA);
  762         pCmd->Action = htole16(dirSet);
  763         if (ant == 0)                   /* default to all/both antennae */
  764                 ant = 3;
  765         pCmd->AntennaMode = htole16(ant);
  766 
  767         retval = mwlExecuteCmd(mh, HostCmd_CMD_802_11_RF_ANTENNA);
  768         MWL_HAL_UNLOCK(mh);
  769         return retval;
  770 }
  771 
  772 /*
  773  * Set packet size threshold for implicit use of RTS.
  774  * Takes effect immediately.
  775  * XXX packet length > threshold =>'s RTS
  776  */
  777 int
  778 mwl_hal_setrtsthreshold(struct mwl_hal_vap *vap, int threshold)
  779 {
  780         struct mwl_hal_priv *mh = MWLVAP(vap);
  781         HostCmd_DS_802_11_RTS_THSD *pCmd;
  782         int retval;
  783 
  784         MWL_HAL_LOCK(mh);
  785         _VCMD_SETUP(vap, pCmd, HostCmd_DS_802_11_RTS_THSD,
  786                 HostCmd_CMD_802_11_RTS_THSD);
  787         pCmd->Action  = htole16(HostCmd_ACT_GEN_SET);
  788         pCmd->Threshold = htole16(threshold);
  789 
  790         retval = mwlExecuteCmd(mh, HostCmd_CMD_802_11_RTS_THSD);
  791         MWL_HAL_UNLOCK(mh);
  792         return retval;
  793 }
  794 
  795 /*
  796  * Enable sta-mode operation (disables beacon frame xmit).
  797  */
  798 int
  799 mwl_hal_setinframode(struct mwl_hal_vap *vap)
  800 {
  801         struct mwl_hal_priv *mh = MWLVAP(vap);
  802         HostCmd_FW_SET_INFRA_MODE *pCmd;
  803         int retval;
  804 
  805         MWL_HAL_LOCK(mh);
  806         _VCMD_SETUP(vap, pCmd, HostCmd_FW_SET_INFRA_MODE,
  807                 HostCmd_CMD_SET_INFRA_MODE);
  808 
  809         retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_INFRA_MODE);
  810         MWL_HAL_UNLOCK(mh);
  811         return retval;
  812 }
  813 
  814 /*
  815  * Configure radar detection in support of 802.11h.
  816  */
  817 int
  818 mwl_hal_setradardetection(struct mwl_hal *mh0, MWL_HAL_RADAR action)
  819 {
  820         struct mwl_hal_priv *mh = MWLPRIV(mh0);
  821         HostCmd_802_11h_Detect_Radar *pCmd;
  822         int retval;
  823 
  824         MWL_HAL_LOCK(mh);
  825         _CMD_SETUP(pCmd, HostCmd_802_11h_Detect_Radar,
  826                 HostCmd_CMD_802_11H_DETECT_RADAR);
  827         pCmd->CmdHdr.Length = htole16(sizeof(HostCmd_802_11h_Detect_Radar));
  828         pCmd->Action = htole16(action);
  829         if (mh->mh_regioncode == DOMAIN_CODE_ETSI_131)
  830                 pCmd->RadarTypeCode = htole16(131);
  831 
  832         retval = mwlExecuteCmd(mh, HostCmd_CMD_802_11H_DETECT_RADAR);
  833         MWL_HAL_UNLOCK(mh);
  834         return retval;
  835 } 
  836 
  837 /*
  838  * Convert public channel flags definition to a
  839  * value suitable for feeding to the firmware.
  840  * Note this includes byte swapping.
  841  */
  842 static uint32_t
  843 cvtChannelFlags(const MWL_HAL_CHANNEL *chan)
  844 {
  845         uint32_t w;
  846 
  847         /*
  848          * NB: f/w only understands FREQ_BAND_5GHZ, supplying the more
  849          *     precise band info causes it to lockup (sometimes).
  850          */
  851         w = (chan->channelFlags.FreqBand == MWL_FREQ_BAND_2DOT4GHZ) ?
  852                 FREQ_BAND_2DOT4GHZ : FREQ_BAND_5GHZ;
  853         switch (chan->channelFlags.ChnlWidth) {
  854         case MWL_CH_10_MHz_WIDTH:
  855                 w |= CH_10_MHz_WIDTH;
  856                 break;
  857         case MWL_CH_20_MHz_WIDTH:
  858                 w |= CH_20_MHz_WIDTH;
  859                 break;
  860         case MWL_CH_40_MHz_WIDTH:
  861         default:
  862                 w |= CH_40_MHz_WIDTH;
  863                 break;
  864         }
  865         switch (chan->channelFlags.ExtChnlOffset) {
  866         case MWL_EXT_CH_NONE:
  867                 w |= EXT_CH_NONE;
  868                 break;
  869         case MWL_EXT_CH_ABOVE_CTRL_CH:
  870                 w |= EXT_CH_ABOVE_CTRL_CH;
  871                 break;
  872         case MWL_EXT_CH_BELOW_CTRL_CH:
  873                 w |= EXT_CH_BELOW_CTRL_CH;
  874                 break;
  875         }
  876         return htole32(w);
  877 }
  878 
  879 /*
  880  * Start a channel switch announcement countdown.  The IE
  881  * in the beacon frame is allowed to go out and the firmware
  882  * counts down and notifies the host when it's time to switch
  883  * channels.
  884  */
  885 int
  886 mwl_hal_setchannelswitchie(struct mwl_hal *mh0,
  887         const MWL_HAL_CHANNEL *nextchan, uint32_t mode, uint32_t count)
  888 {
  889         struct mwl_hal_priv *mh = MWLPRIV(mh0);
  890         HostCmd_SET_SWITCH_CHANNEL *pCmd;
  891         int retval;
  892 
  893         MWL_HAL_LOCK(mh);
  894         _CMD_SETUP(pCmd, HostCmd_SET_SWITCH_CHANNEL,
  895                 HostCmd_CMD_SET_SWITCH_CHANNEL);
  896         pCmd->Next11hChannel = htole32(nextchan->channel);
  897         pCmd->Mode = htole32(mode);
  898         pCmd->InitialCount = htole32(count+1);
  899         pCmd->ChannelFlags = cvtChannelFlags(nextchan);
  900 
  901         retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_SWITCH_CHANNEL);
  902         MWL_HAL_UNLOCK(mh);
  903         return retval;
  904 }
  905 
  906 /*
  907  * Set the region code that selects the radar bin'ing agorithm.
  908  */
  909 int
  910 mwl_hal_setregioncode(struct mwl_hal *mh0, int regionCode)
  911 {
  912         struct mwl_hal_priv *mh = MWLPRIV(mh0);
  913         HostCmd_SET_REGIONCODE_INFO *pCmd;
  914         int retval;
  915 
  916         MWL_HAL_LOCK(mh);
  917         _CMD_SETUP(pCmd, HostCmd_SET_REGIONCODE_INFO,
  918                 HostCmd_CMD_SET_REGION_CODE);
  919         /* XXX map pseudo-codes to fw codes */
  920         switch (regionCode) {
  921         case DOMAIN_CODE_ETSI_131:
  922                 pCmd->regionCode = htole16(DOMAIN_CODE_ETSI);
  923                 break;
  924         default:
  925                 pCmd->regionCode = htole16(regionCode);
  926                 break;
  927         }
  928 
  929         retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_REGION_CODE);
  930         if (retval == 0)
  931                 mh->mh_regioncode = regionCode;
  932         MWL_HAL_UNLOCK(mh);
  933         return retval;
  934 }
  935 
  936 #define RATEVAL(r)      ((r) &~ RATE_MCS)
  937 #define RATETYPE(r)     (((r) & RATE_MCS) ? HT_RATE_TYPE : LEGACY_RATE_TYPE)
  938 
  939 int
  940 mwl_hal_settxrate(struct mwl_hal_vap *vap, MWL_HAL_TXRATE_HANDLING handling,
  941         const MWL_HAL_TXRATE *rate)
  942 {
  943         struct mwl_hal_priv *mh = MWLVAP(vap);
  944         HostCmd_FW_USE_FIXED_RATE *pCmd;
  945         FIXED_RATE_ENTRY *fp;
  946         int retval, i, n;
  947 
  948         MWL_HAL_LOCK(mh);
  949         _VCMD_SETUP(vap, pCmd, HostCmd_FW_USE_FIXED_RATE,
  950                 HostCmd_CMD_SET_FIXED_RATE);
  951 
  952         pCmd->MulticastRate = RATEVAL(rate->McastRate);
  953         pCmd->MultiRateTxType = RATETYPE(rate->McastRate);
  954         /* NB: no rate type field */
  955         pCmd->ManagementRate = RATEVAL(rate->MgtRate);
  956         memset(pCmd->FixedRateTable, 0, sizeof(pCmd->FixedRateTable));
  957         if (handling == RATE_FIXED) {
  958                 pCmd->Action = htole32(HostCmd_ACT_GEN_SET);
  959                 pCmd->AllowRateDrop = htole32(FIXED_RATE_WITHOUT_AUTORATE_DROP);
  960                 fp = pCmd->FixedRateTable;
  961                 fp->FixedRate =
  962                     htole32(RATEVAL(rate->RateSeries[0].Rate));
  963                 fp->FixRateTypeFlags.FixRateType =
  964                     htole32(RATETYPE(rate->RateSeries[0].Rate));
  965                 pCmd->EntryCount = htole32(1);
  966         } else if (handling == RATE_FIXED_DROP) {
  967                 pCmd->Action = htole32(HostCmd_ACT_GEN_SET);
  968                 pCmd->AllowRateDrop = htole32(FIXED_RATE_WITH_AUTO_RATE_DROP);
  969                 n = 0;
  970                 fp = pCmd->FixedRateTable;
  971                 for (i = 0; i < 4; i++) {
  972                         if (rate->RateSeries[0].TryCount == 0)
  973                                 break;
  974                         fp->FixRateTypeFlags.FixRateType =
  975                             htole32(RATETYPE(rate->RateSeries[i].Rate));
  976                         fp->FixedRate =
  977                             htole32(RATEVAL(rate->RateSeries[i].Rate));
  978                         fp->FixRateTypeFlags.RetryCountValid =
  979                             htole32(RETRY_COUNT_VALID);
  980                         fp->RetryCount =
  981                             htole32(rate->RateSeries[i].TryCount-1);
  982                         n++;
  983                 }
  984                 pCmd->EntryCount = htole32(n);
  985         } else 
  986                 pCmd->Action = htole32(HostCmd_ACT_NOT_USE_FIXED_RATE);
  987 
  988         retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_FIXED_RATE);
  989         MWL_HAL_UNLOCK(mh);
  990         return retval;
  991 }
  992 
  993 int
  994 mwl_hal_settxrate_auto(struct mwl_hal *mh0, const MWL_HAL_TXRATE *rate)
  995 {
  996         struct mwl_hal_priv *mh = MWLPRIV(mh0);
  997         HostCmd_FW_USE_FIXED_RATE *pCmd;
  998         int retval;
  999 
 1000         MWL_HAL_LOCK(mh);
 1001         _CMD_SETUP(pCmd, HostCmd_FW_USE_FIXED_RATE,
 1002                 HostCmd_CMD_SET_FIXED_RATE);
 1003 
 1004         pCmd->MulticastRate = RATEVAL(rate->McastRate);
 1005         pCmd->MultiRateTxType = RATETYPE(rate->McastRate);
 1006         /* NB: no rate type field */
 1007         pCmd->ManagementRate = RATEVAL(rate->MgtRate);
 1008         memset(pCmd->FixedRateTable, 0, sizeof(pCmd->FixedRateTable));
 1009         pCmd->Action = htole32(HostCmd_ACT_NOT_USE_FIXED_RATE);
 1010 
 1011         retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_FIXED_RATE);
 1012         MWL_HAL_UNLOCK(mh);
 1013         return retval;
 1014 }
 1015 
 1016 #undef RATEVAL
 1017 #undef RATETYPE
 1018 
 1019 int
 1020 mwl_hal_setslottime(struct mwl_hal *mh0, int usecs)
 1021 {
 1022         struct mwl_hal_priv *mh = MWLPRIV(mh0);
 1023         HostCmd_FW_SET_SLOT *pCmd;
 1024         int retval;
 1025 
 1026         if (usecs != 9 && usecs != 20)
 1027                 return EINVAL;
 1028 
 1029         MWL_HAL_LOCK(mh);
 1030         _CMD_SETUP(pCmd, HostCmd_FW_SET_SLOT,
 1031             HostCmd_CMD_802_11_SET_SLOT);
 1032         pCmd->Action = htole16(HostCmd_ACT_GEN_SET);
 1033         pCmd->Slot = (usecs == 9 ? 1 : 0);
 1034 
 1035         retval = mwlExecuteCmd(mh, HostCmd_CMD_802_11_SET_SLOT);
 1036         MWL_HAL_UNLOCK(mh);
 1037         return retval;
 1038 }
 1039 
 1040 int
 1041 mwl_hal_adjusttxpower(struct mwl_hal *mh0, uint32_t level)
 1042 {
 1043         struct mwl_hal_priv *mh = MWLPRIV(mh0);
 1044         HostCmd_DS_802_11_RF_TX_POWER *pCmd;
 1045         int retval;
 1046 
 1047         MWL_HAL_LOCK(mh);
 1048         _CMD_SETUP(pCmd, HostCmd_DS_802_11_RF_TX_POWER,
 1049             HostCmd_CMD_802_11_RF_TX_POWER);
 1050         pCmd->Action = htole16(HostCmd_ACT_GEN_SET);
 1051 
 1052         if (level < 30) {
 1053                 pCmd->SupportTxPowerLevel = htole16(WL_TX_POWERLEVEL_LOW);
 1054         } else if (level >= 30 && level < 60) {
 1055                 pCmd->SupportTxPowerLevel = htole16(WL_TX_POWERLEVEL_MEDIUM);
 1056         } else {
 1057                 pCmd->SupportTxPowerLevel = htole16(WL_TX_POWERLEVEL_HIGH);
 1058         }
 1059 
 1060         retval = mwlExecuteCmd(mh, HostCmd_CMD_802_11_RF_TX_POWER);
 1061         MWL_HAL_UNLOCK(mh);
 1062         return retval;
 1063 }
 1064 
 1065 static const struct mwl_hal_channel *
 1066 findchannel(const struct mwl_hal_priv *mh, const MWL_HAL_CHANNEL *c)
 1067 {
 1068         const struct mwl_hal_channel *hc;
 1069         const MWL_HAL_CHANNELINFO *ci;
 1070         int chan = c->channel, i;
 1071 
 1072         if (c->channelFlags.FreqBand == MWL_FREQ_BAND_2DOT4GHZ) {
 1073                 i = chan - 1;
 1074                 if (c->channelFlags.ChnlWidth == MWL_CH_40_MHz_WIDTH) {
 1075                         ci = &mh->mh_40M;
 1076                         if (c->channelFlags.ExtChnlOffset == MWL_EXT_CH_BELOW_CTRL_CH)
 1077                                 i -= 4;
 1078                 } else
 1079                         ci = &mh->mh_20M;
 1080                 /* 2.4G channel table is directly indexed */
 1081                 hc = ((unsigned)i < ci->nchannels) ? &ci->channels[i] : NULL;
 1082         } else if (c->channelFlags.FreqBand == MWL_FREQ_BAND_5GHZ) {
 1083                 if (c->channelFlags.ChnlWidth == MWL_CH_40_MHz_WIDTH) {
 1084                         ci = &mh->mh_40M_5G;
 1085                         if (c->channelFlags.ExtChnlOffset == MWL_EXT_CH_BELOW_CTRL_CH)
 1086                                 chan -= 4;
 1087                 } else
 1088                         ci = &mh->mh_20M_5G;
 1089                 /* 5GHz channel table is sparse and must be searched */
 1090                 for (i = 0; i < ci->nchannels; i++)
 1091                         if (ci->channels[i].ieee == chan)
 1092                                 break;
 1093                 hc = (i < ci->nchannels) ? &ci->channels[i] : NULL;
 1094         } else
 1095                 hc = NULL;
 1096         return hc;
 1097 }
 1098 
 1099 int
 1100 mwl_hal_settxpower(struct mwl_hal *mh0, const MWL_HAL_CHANNEL *c, uint8_t maxtxpow)
 1101 {
 1102         struct mwl_hal_priv *mh = MWLPRIV(mh0);
 1103         HostCmd_DS_802_11_RF_TX_POWER *pCmd;
 1104         const struct mwl_hal_channel *hc;
 1105         int i, retval;
 1106 
 1107         hc = findchannel(mh, c);
 1108         if (hc == NULL) {
 1109                 /* XXX temp while testing */
 1110                 device_printf(mh->mh_dev,
 1111                     "%s: no cal data for channel %u band %u width %u ext %u\n",
 1112                     __func__, c->channel, c->channelFlags.FreqBand,
 1113                     c->channelFlags.ChnlWidth, c->channelFlags.ExtChnlOffset);
 1114                 return EINVAL;
 1115         }
 1116 
 1117         MWL_HAL_LOCK(mh);
 1118         _CMD_SETUP(pCmd, HostCmd_DS_802_11_RF_TX_POWER,
 1119             HostCmd_CMD_802_11_RF_TX_POWER);
 1120         pCmd->Action = htole16(HostCmd_ACT_GEN_SET_LIST);
 1121         i = 0;
 1122         /* NB: 5Ghz cal data have the channel # in [0]; don't truncate */
 1123         if (c->channelFlags.FreqBand == MWL_FREQ_BAND_5GHZ)
 1124                 pCmd->PowerLevelList[i++] = htole16(hc->targetPowers[0]);
 1125         for (; i < 4; i++) {
 1126                 uint16_t pow = hc->targetPowers[i];
 1127                 if (pow > maxtxpow)
 1128                         pow = maxtxpow;
 1129                 pCmd->PowerLevelList[i] = htole16(pow);
 1130         }
 1131         retval = mwlExecuteCmd(mh, HostCmd_CMD_802_11_RF_TX_POWER);
 1132         MWL_HAL_UNLOCK(mh);
 1133         return retval;
 1134 }
 1135 
 1136 int
 1137 mwl_hal_getchannelinfo(struct mwl_hal *mh0, int band, int chw,
 1138         const MWL_HAL_CHANNELINFO **ci)
 1139 {
 1140         struct mwl_hal_priv *mh = MWLPRIV(mh0);
 1141 
 1142         switch (band) {
 1143         case MWL_FREQ_BAND_2DOT4GHZ:
 1144                 *ci = (chw == MWL_CH_20_MHz_WIDTH) ? &mh->mh_20M : &mh->mh_40M;
 1145                 break;
 1146         case MWL_FREQ_BAND_5GHZ:
 1147                 *ci = (chw == MWL_CH_20_MHz_WIDTH) ?
 1148                      &mh->mh_20M_5G : &mh->mh_40M_5G;
 1149                 break;
 1150         default:
 1151                 return EINVAL;
 1152         }
 1153         return ((*ci)->freqLow == (*ci)->freqHigh) ? EINVAL : 0;
 1154 }
 1155 
 1156 int
 1157 mwl_hal_setmcast(struct mwl_hal *mh0, int nmc, const uint8_t macs[])
 1158 {
 1159         struct mwl_hal_priv *mh = MWLPRIV(mh0);
 1160         HostCmd_DS_MAC_MULTICAST_ADR *pCmd;
 1161         int retval;
 1162 
 1163         if (nmc > MWL_HAL_MCAST_MAX)
 1164                 return EINVAL;
 1165 
 1166         MWL_HAL_LOCK(mh);
 1167         _CMD_SETUP(pCmd, HostCmd_DS_MAC_MULTICAST_ADR,
 1168                 HostCmd_CMD_MAC_MULTICAST_ADR);
 1169         memcpy(pCmd->MACList, macs, nmc*IEEE80211_ADDR_LEN);
 1170         pCmd->NumOfAdrs = htole16(nmc);
 1171         pCmd->Action = htole16(0xffff);
 1172 
 1173         retval = mwlExecuteCmd(mh, HostCmd_CMD_MAC_MULTICAST_ADR);
 1174         MWL_HAL_UNLOCK(mh);
 1175         return retval;
 1176 }
 1177 
 1178 int
 1179 mwl_hal_keyset(struct mwl_hal_vap *vap, const MWL_HAL_KEYVAL *kv,
 1180         const uint8_t mac[IEEE80211_ADDR_LEN])
 1181 {
 1182         struct mwl_hal_priv *mh = MWLVAP(vap);
 1183         HostCmd_FW_UPDATE_ENCRYPTION_SET_KEY *pCmd;
 1184         int retval;
 1185 
 1186         MWL_HAL_LOCK(mh);
 1187         _VCMD_SETUP(vap, pCmd, HostCmd_FW_UPDATE_ENCRYPTION_SET_KEY,
 1188                 HostCmd_CMD_UPDATE_ENCRYPTION);
 1189         if (kv->keyFlags & (KEY_FLAG_TXGROUPKEY|KEY_FLAG_RXGROUPKEY))
 1190                 pCmd->ActionType = htole32(EncrActionTypeSetGroupKey);
 1191         else
 1192                 pCmd->ActionType = htole32(EncrActionTypeSetKey);
 1193         pCmd->KeyParam.Length = htole16(sizeof(pCmd->KeyParam));
 1194         pCmd->KeyParam.KeyTypeId = htole16(kv->keyTypeId);
 1195         pCmd->KeyParam.KeyInfo = htole32(kv->keyFlags);
 1196         pCmd->KeyParam.KeyIndex = htole32(kv->keyIndex);
 1197         /* NB: includes TKIP MIC keys */
 1198         memcpy(&pCmd->KeyParam.Key, &kv->key, kv->keyLen);
 1199         switch (kv->keyTypeId) {
 1200         case KEY_TYPE_ID_WEP:
 1201                 pCmd->KeyParam.KeyLen = htole16(kv->keyLen);
 1202                 break;
 1203         case KEY_TYPE_ID_TKIP:
 1204                 pCmd->KeyParam.KeyLen = htole16(sizeof(TKIP_TYPE_KEY));
 1205                 pCmd->KeyParam.Key.TkipKey.TkipRsc.low =
 1206                         htole16(kv->key.tkip.rsc.low);
 1207                 pCmd->KeyParam.Key.TkipKey.TkipRsc.high =
 1208                         htole32(kv->key.tkip.rsc.high);
 1209                 pCmd->KeyParam.Key.TkipKey.TkipTsc.low =
 1210                         htole16(kv->key.tkip.tsc.low);
 1211                 pCmd->KeyParam.Key.TkipKey.TkipTsc.high =
 1212                         htole32(kv->key.tkip.tsc.high);
 1213                 break;
 1214         case KEY_TYPE_ID_AES:
 1215                 pCmd->KeyParam.KeyLen = htole16(sizeof(AES_TYPE_KEY));
 1216                 break;
 1217         }
 1218 #ifdef MWL_MBSS_SUPPORT
 1219         IEEE80211_ADDR_COPY(pCmd->KeyParam.Macaddr, mac);
 1220 #else
 1221         IEEE80211_ADDR_COPY(pCmd->Macaddr, mac);
 1222 #endif
 1223         retval = mwlExecuteCmd(mh, HostCmd_CMD_UPDATE_ENCRYPTION);
 1224         MWL_HAL_UNLOCK(mh);
 1225         return retval;
 1226 }
 1227 
 1228 int
 1229 mwl_hal_keyreset(struct mwl_hal_vap *vap, const MWL_HAL_KEYVAL *kv, const uint8_t mac[IEEE80211_ADDR_LEN])
 1230 {
 1231         struct mwl_hal_priv *mh = MWLVAP(vap);
 1232         HostCmd_FW_UPDATE_ENCRYPTION_SET_KEY *pCmd;
 1233         int retval;
 1234 
 1235         MWL_HAL_LOCK(mh);
 1236         _VCMD_SETUP(vap, pCmd, HostCmd_FW_UPDATE_ENCRYPTION_SET_KEY,
 1237                 HostCmd_CMD_UPDATE_ENCRYPTION);
 1238         pCmd->ActionType = htole16(EncrActionTypeRemoveKey);
 1239         pCmd->KeyParam.Length = htole16(sizeof(pCmd->KeyParam));
 1240         pCmd->KeyParam.KeyTypeId = htole16(kv->keyTypeId);
 1241         pCmd->KeyParam.KeyInfo = htole32(kv->keyFlags);
 1242         pCmd->KeyParam.KeyIndex = htole32(kv->keyIndex);
 1243 #ifdef MWL_MBSS_SUPPORT
 1244         IEEE80211_ADDR_COPY(pCmd->KeyParam.Macaddr, mac);
 1245 #else
 1246         IEEE80211_ADDR_COPY(pCmd->Macaddr, mac);
 1247 #endif
 1248         retval = mwlExecuteCmd(mh, HostCmd_CMD_UPDATE_ENCRYPTION);
 1249         MWL_HAL_UNLOCK(mh);
 1250         return retval;
 1251 }
 1252 
 1253 static int
 1254 mwl_hal_setmac_locked(struct mwl_hal_vap *vap,
 1255         const uint8_t addr[IEEE80211_ADDR_LEN])
 1256 {
 1257         struct mwl_hal_priv *mh = MWLVAP(vap);
 1258         HostCmd_DS_SET_MAC *pCmd;
 1259 
 1260         _VCMD_SETUP(vap, pCmd, HostCmd_DS_SET_MAC, HostCmd_CMD_SET_MAC_ADDR);
 1261         IEEE80211_ADDR_COPY(&pCmd->MacAddr[0], addr);
 1262 #ifdef MWL_MBSS_SUPPORT
 1263         pCmd->MacType = vap->bss_type;          /* NB: already byte swapped */
 1264         IEEE80211_ADDR_COPY(vap->mac, addr);    /* XXX do only if success */
 1265 #endif
 1266         return mwlExecuteCmd(mh, HostCmd_CMD_SET_MAC_ADDR);
 1267 }
 1268 
 1269 int
 1270 mwl_hal_setmac(struct mwl_hal_vap *vap, const uint8_t addr[IEEE80211_ADDR_LEN])
 1271 {
 1272         struct mwl_hal_priv *mh = MWLVAP(vap);
 1273         int retval;
 1274 
 1275         MWL_HAL_LOCK(mh);
 1276         retval = mwl_hal_setmac_locked(vap, addr);
 1277         MWL_HAL_UNLOCK(mh);
 1278         return retval;
 1279 }
 1280 
 1281 int
 1282 mwl_hal_setbeacon(struct mwl_hal_vap *vap, const void *frame, size_t frameLen)
 1283 {
 1284         struct mwl_hal_priv *mh = MWLVAP(vap);
 1285         HostCmd_DS_SET_BEACON *pCmd;
 1286         int retval;
 1287 
 1288         /* XXX verify frameLen fits */
 1289         MWL_HAL_LOCK(mh);
 1290         _VCMD_SETUP(vap, pCmd, HostCmd_DS_SET_BEACON, HostCmd_CMD_SET_BEACON);
 1291         /* XXX override _VCMD_SETUP */
 1292         pCmd->CmdHdr.Length = htole16(sizeof(HostCmd_DS_SET_BEACON)-1+frameLen);
 1293         pCmd->FrmBodyLen = htole16(frameLen);
 1294         memcpy(pCmd->FrmBody, frame, frameLen);
 1295 
 1296         retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_BEACON);
 1297         MWL_HAL_UNLOCK(mh);
 1298         return retval;
 1299 }
 1300 
 1301 int
 1302 mwl_hal_setpowersave_bss(struct mwl_hal_vap *vap, uint8_t nsta)
 1303 {
 1304         struct mwl_hal_priv *mh = MWLVAP(vap);
 1305         HostCmd_SET_POWERSAVESTATION *pCmd;
 1306         int retval;
 1307 
 1308         MWL_HAL_LOCK(mh);
 1309         _VCMD_SETUP(vap, pCmd, HostCmd_SET_POWERSAVESTATION,
 1310                 HostCmd_CMD_SET_POWERSAVESTATION);
 1311         pCmd->NumberOfPowersave = nsta;
 1312 
 1313         retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_POWERSAVESTATION);
 1314         MWL_HAL_UNLOCK(mh);
 1315         return retval;
 1316 }
 1317 
 1318 int
 1319 mwl_hal_setpowersave_sta(struct mwl_hal_vap *vap, uint16_t aid, int ena)
 1320 {
 1321         struct mwl_hal_priv *mh = MWLVAP(vap);
 1322         HostCmd_SET_TIM *pCmd;
 1323         int retval;
 1324 
 1325         MWL_HAL_LOCK(mh);
 1326         _VCMD_SETUP(vap, pCmd, HostCmd_SET_TIM, HostCmd_CMD_SET_TIM);
 1327         pCmd->Aid = htole16(aid);
 1328         pCmd->Set = htole32(ena);
 1329 
 1330         retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_TIM);
 1331         MWL_HAL_UNLOCK(mh);
 1332         return retval;
 1333 }
 1334 
 1335 int
 1336 mwl_hal_setassocid(struct mwl_hal_vap *vap,
 1337         const uint8_t bssId[IEEE80211_ADDR_LEN], uint16_t assocId)
 1338 {
 1339         struct mwl_hal_priv *mh = MWLVAP(vap);
 1340         HostCmd_FW_SET_AID *pCmd = (HostCmd_FW_SET_AID *) &mh->mh_cmdbuf[0];
 1341         int retval;
 1342 
 1343         MWL_HAL_LOCK(mh);
 1344         _VCMD_SETUP(vap, pCmd, HostCmd_FW_SET_AID, HostCmd_CMD_SET_AID);
 1345         pCmd->AssocID = htole16(assocId);
 1346         IEEE80211_ADDR_COPY(&pCmd->MacAddr[0], bssId);
 1347 
 1348         retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_AID);
 1349         MWL_HAL_UNLOCK(mh);
 1350         return retval;
 1351 }
 1352 
 1353 int
 1354 mwl_hal_setchannel(struct mwl_hal *mh0, const MWL_HAL_CHANNEL *chan)
 1355 {
 1356         struct mwl_hal_priv *mh = MWLPRIV(mh0);
 1357         HostCmd_FW_SET_RF_CHANNEL *pCmd;
 1358         int retval;
 1359 
 1360         MWL_HAL_LOCK(mh);
 1361         _CMD_SETUP(pCmd, HostCmd_FW_SET_RF_CHANNEL, HostCmd_CMD_SET_RF_CHANNEL);
 1362         pCmd->Action = htole16(HostCmd_ACT_GEN_SET);
 1363         pCmd->CurrentChannel = chan->channel;
 1364         pCmd->ChannelFlags = cvtChannelFlags(chan);     /* NB: byte-swapped */
 1365 
 1366         retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_RF_CHANNEL);
 1367         MWL_HAL_UNLOCK(mh);
 1368         return retval;
 1369 }
 1370 
 1371 static int
 1372 bastream_check_available(struct mwl_hal_vap *vap, int qid,
 1373         const uint8_t Macaddr[IEEE80211_ADDR_LEN],
 1374         uint8_t Tid, uint8_t ParamInfo)
 1375 {
 1376         struct mwl_hal_priv *mh = MWLVAP(vap);
 1377         HostCmd_FW_BASTREAM *pCmd;
 1378         int retval;
 1379 
 1380         MWL_HAL_LOCK_ASSERT(mh);
 1381 
 1382         _VCMD_SETUP(vap, pCmd, HostCmd_FW_BASTREAM, HostCmd_CMD_BASTREAM);
 1383         pCmd->ActionType = htole32(BaCheckCreateStream);
 1384         pCmd->BaInfo.CreateParams.BarThrs = htole32(63);
 1385         pCmd->BaInfo.CreateParams.WindowSize = htole32(64); 
 1386         pCmd->BaInfo.CreateParams.IdleThrs = htole32(0x22000);
 1387         IEEE80211_ADDR_COPY(&pCmd->BaInfo.CreateParams.PeerMacAddr[0], Macaddr);
 1388         pCmd->BaInfo.CreateParams.DialogToken = 10;
 1389         pCmd->BaInfo.CreateParams.Tid = Tid;
 1390         pCmd->BaInfo.CreateParams.QueueId = qid;
 1391         pCmd->BaInfo.CreateParams.ParamInfo = (uint8_t) ParamInfo;
 1392 #if 0
 1393         cvtBAFlags(&pCmd->BaInfo.CreateParams.Flags, sp->ba_policy, 0);
 1394 #else
 1395         pCmd->BaInfo.CreateParams.Flags =
 1396                           htole32(BASTREAM_FLAG_IMMEDIATE_TYPE)
 1397                         | htole32(BASTREAM_FLAG_DIRECTION_UPSTREAM)
 1398                         ;
 1399 #endif
 1400 
 1401         retval = mwlExecuteCmd(mh, HostCmd_CMD_BASTREAM);
 1402         if (retval == 0) {
 1403                 /*
 1404                  * NB: BA stream create may fail when the stream is
 1405                  * h/w backed under some (as yet not understood) conditions.
 1406                  * Check the result code to catch this.
 1407                  */
 1408                 if (le16toh(pCmd->CmdHdr.Result) != HostCmd_RESULT_OK)
 1409                         retval = EIO;
 1410         }
 1411         return retval;
 1412 }
 1413 
 1414 const MWL_HAL_BASTREAM *
 1415 mwl_hal_bastream_alloc(struct mwl_hal_vap *vap, int ba_policy,
 1416         const uint8_t Macaddr[IEEE80211_ADDR_LEN],
 1417         uint8_t Tid, uint8_t ParamInfo, void *a1, void *a2)
 1418 {
 1419         struct mwl_hal_priv *mh = MWLVAP(vap);
 1420         struct mwl_hal_bastream *sp;
 1421         int s;
 1422 
 1423         MWL_HAL_LOCK(mh);
 1424         if (mh->mh_bastreams == 0) {
 1425                 /* no streams available */
 1426                 MWL_HAL_UNLOCK(mh);
 1427                 return NULL;
 1428         }
 1429         for (s = 0; (mh->mh_bastreams & (1<<s)) == 0; s++)
 1430                 ;
 1431         if (bastream_check_available(vap, s, Macaddr, Tid, ParamInfo)) {
 1432                 MWL_HAL_UNLOCK(mh);
 1433                 return NULL;
 1434         }
 1435         sp = &mh->mh_streams[s];
 1436         mh->mh_bastreams &= ~(1<<s);
 1437         sp->public.data[0] = a1;
 1438         sp->public.data[1] = a2;
 1439         IEEE80211_ADDR_COPY(sp->macaddr, Macaddr);
 1440         sp->tid = Tid;
 1441         sp->paraminfo = ParamInfo;
 1442         sp->setup = 0;
 1443         sp->ba_policy = ba_policy;
 1444         MWL_HAL_UNLOCK(mh);
 1445         return &sp->public;
 1446 }
 1447 
 1448 const MWL_HAL_BASTREAM *
 1449 mwl_hal_bastream_lookup(struct mwl_hal *mh0, int s)
 1450 {
 1451         struct mwl_hal_priv *mh = MWLPRIV(mh0);
 1452 
 1453         if (!(0 <= s && s < MWL_BASTREAMS_MAX))
 1454                 return NULL;
 1455         if (mh->mh_bastreams & (1<<s))
 1456                 return NULL;
 1457         return &mh->mh_streams[s].public;
 1458 }
 1459 
 1460 #ifndef __DECONST
 1461 #define __DECONST(type, var)    ((type)(uintptr_t)(const void *)(var))
 1462 #endif
 1463 
 1464 int
 1465 mwl_hal_bastream_create(struct mwl_hal_vap *vap,
 1466         const MWL_HAL_BASTREAM *s, int BarThrs, int WindowSize, uint16_t seqno)
 1467 {
 1468         struct mwl_hal_priv *mh = MWLVAP(vap);
 1469         struct mwl_hal_bastream *sp = __DECONST(struct mwl_hal_bastream *, s);
 1470         HostCmd_FW_BASTREAM *pCmd;
 1471         int retval;
 1472 
 1473         MWL_HAL_LOCK(mh);
 1474         _VCMD_SETUP(vap, pCmd, HostCmd_FW_BASTREAM, HostCmd_CMD_BASTREAM);
 1475         pCmd->ActionType = htole32(BaCreateStream);
 1476         pCmd->BaInfo.CreateParams.BarThrs = htole32(BarThrs);
 1477         pCmd->BaInfo.CreateParams.WindowSize = htole32(WindowSize);
 1478         pCmd->BaInfo.CreateParams.IdleThrs = htole32(0x22000);
 1479         IEEE80211_ADDR_COPY(&pCmd->BaInfo.CreateParams.PeerMacAddr[0],
 1480             sp->macaddr);
 1481         /* XXX proxy STA */
 1482         memset(&pCmd->BaInfo.CreateParams.StaSrcMacAddr, 0, IEEE80211_ADDR_LEN);
 1483 #if 0
 1484         pCmd->BaInfo.CreateParams.DialogToken = DialogToken;
 1485 #else
 1486         pCmd->BaInfo.CreateParams.DialogToken = 10;
 1487 #endif
 1488         pCmd->BaInfo.CreateParams.Tid = sp->tid;
 1489         pCmd->BaInfo.CreateParams.QueueId = sp->stream;
 1490         pCmd->BaInfo.CreateParams.ParamInfo = sp->paraminfo;
 1491         /* NB: ResetSeqNo known to be zero */
 1492         pCmd->BaInfo.CreateParams.StartSeqNo = htole16(seqno);
 1493 #if 0
 1494         cvtBAFlags(&pCmd->BaInfo.CreateParams.Flags, sp->ba_policy, 0);
 1495 #else
 1496         pCmd->BaInfo.CreateParams.Flags =
 1497                           htole32(BASTREAM_FLAG_IMMEDIATE_TYPE)
 1498                         | htole32(BASTREAM_FLAG_DIRECTION_UPSTREAM)
 1499                         ;
 1500 #endif
 1501 
 1502         retval = mwlExecuteCmd(mh, HostCmd_CMD_BASTREAM);
 1503         if (retval == 0) {
 1504                 /*
 1505                  * NB: BA stream create may fail when the stream is
 1506                  * h/w backed under some (as yet not understood) conditions.
 1507                  * Check the result code to catch this.
 1508                  */
 1509                 if (le16toh(pCmd->CmdHdr.Result) != HostCmd_RESULT_OK)
 1510                         retval = EIO;
 1511                 else
 1512                         sp->setup = 1;
 1513         }
 1514         MWL_HAL_UNLOCK(mh);
 1515         return retval;
 1516 }
 1517 
 1518 int
 1519 mwl_hal_bastream_destroy(struct mwl_hal *mh0, const MWL_HAL_BASTREAM *s)
 1520 {
 1521         struct mwl_hal_priv *mh = MWLPRIV(mh0);
 1522         struct mwl_hal_bastream *sp = __DECONST(struct mwl_hal_bastream *, s);
 1523         HostCmd_FW_BASTREAM *pCmd;
 1524         int retval;
 1525 
 1526         if (sp->stream >= MWL_BASTREAMS_MAX) {
 1527                 /* XXX */
 1528                 return EINVAL;
 1529         }
 1530         MWL_HAL_LOCK(mh);
 1531         if (sp->setup) {
 1532                 _CMD_SETUP(pCmd, HostCmd_FW_BASTREAM, HostCmd_CMD_BASTREAM);
 1533                 pCmd->ActionType = htole32(BaDestroyStream);
 1534                 pCmd->BaInfo.DestroyParams.FwBaContext.Context =
 1535                     htole32(sp->stream);
 1536 
 1537                 retval = mwlExecuteCmd(mh, HostCmd_CMD_BASTREAM);
 1538         } else
 1539                 retval = 0;
 1540         /* NB: always reclaim stream */
 1541         mh->mh_bastreams |= 1<<sp->stream;
 1542         sp->public.data[0] = NULL;
 1543         sp->public.data[1] = NULL;
 1544         sp->setup = 0;
 1545         MWL_HAL_UNLOCK(mh);
 1546         return retval;
 1547 }
 1548 
 1549 int
 1550 mwl_hal_bastream_get_seqno(struct mwl_hal *mh0,
 1551         const MWL_HAL_BASTREAM *s, const uint8_t Macaddr[IEEE80211_ADDR_LEN],
 1552         uint16_t *pseqno)
 1553 {
 1554         struct mwl_hal_priv *mh = MWLPRIV(mh0);
 1555         struct mwl_hal_bastream *sp = __DECONST(struct mwl_hal_bastream *, s);
 1556         HostCmd_GET_SEQNO *pCmd;
 1557         int retval;
 1558 
 1559         MWL_HAL_LOCK(mh);
 1560         _CMD_SETUP(pCmd, HostCmd_GET_SEQNO, HostCmd_CMD_GET_SEQNO);
 1561         IEEE80211_ADDR_COPY(pCmd->MacAddr, Macaddr);
 1562         pCmd->TID = sp->tid;
 1563 
 1564         retval = mwlExecuteCmd(mh, HostCmd_CMD_GET_SEQNO);
 1565         if (retval == 0)
 1566                 *pseqno = le16toh(pCmd->SeqNo);
 1567         MWL_HAL_UNLOCK(mh);
 1568         return retval;
 1569 }       
 1570 
 1571 int
 1572 mwl_hal_getwatchdogbitmap(struct mwl_hal *mh0, uint8_t bitmap[1])
 1573 {
 1574         struct mwl_hal_priv *mh = MWLPRIV(mh0);
 1575         HostCmd_FW_GET_WATCHDOG_BITMAP *pCmd;
 1576         int retval;
 1577 
 1578         MWL_HAL_LOCK(mh);
 1579         _CMD_SETUP(pCmd, HostCmd_FW_GET_WATCHDOG_BITMAP,
 1580                 HostCmd_CMD_GET_WATCHDOG_BITMAP);
 1581 
 1582         retval = mwlExecuteCmd(mh, HostCmd_CMD_GET_WATCHDOG_BITMAP);
 1583         if (retval == 0) {
 1584                 bitmap[0] = pCmd->Watchdogbitmap;
 1585                 /* fw returns qid, map it to BA stream */
 1586                 if (bitmap[0] < MWL_BAQID_MAX)
 1587                         bitmap[0] = qid2ba[bitmap[0]];
 1588         }
 1589         MWL_HAL_UNLOCK(mh);
 1590         return retval;
 1591 }
 1592 
 1593 /*
 1594  * Configure aggressive Ampdu rate mode.
 1595  */
 1596 int
 1597 mwl_hal_setaggampduratemode(struct mwl_hal *mh0, int mode, int threshold)
 1598 {
 1599         struct mwl_hal_priv *mh = MWLPRIV(mh0);
 1600         HostCmd_FW_AMPDU_RETRY_RATEDROP_MODE *pCmd;
 1601         int retval;
 1602 
 1603         MWL_HAL_LOCK(mh);
 1604         _CMD_SETUP(pCmd, HostCmd_FW_AMPDU_RETRY_RATEDROP_MODE,
 1605                 HostCmd_CMD_AMPDU_RETRY_RATEDROP_MODE);
 1606         pCmd->Action = htole16(1);
 1607         pCmd->Option = htole32(mode);
 1608         pCmd->Threshold = htole32(threshold);
 1609 
 1610         retval = mwlExecuteCmd(mh, HostCmd_CMD_AMPDU_RETRY_RATEDROP_MODE);
 1611         MWL_HAL_UNLOCK(mh);   
 1612         return retval;
 1613 }
 1614 
 1615 int
 1616 mwl_hal_getaggampduratemode(struct mwl_hal *mh0, int *mode, int *threshold)
 1617 {
 1618         struct mwl_hal_priv *mh = MWLPRIV(mh0);
 1619         HostCmd_FW_AMPDU_RETRY_RATEDROP_MODE *pCmd;
 1620         int retval;
 1621 
 1622         MWL_HAL_LOCK(mh);
 1623         _CMD_SETUP(pCmd, HostCmd_FW_AMPDU_RETRY_RATEDROP_MODE,
 1624                 HostCmd_CMD_AMPDU_RETRY_RATEDROP_MODE);
 1625         pCmd->Action = htole16(0);
 1626 
 1627         retval = mwlExecuteCmd(mh, HostCmd_CMD_AMPDU_RETRY_RATEDROP_MODE);
 1628         MWL_HAL_UNLOCK(mh);   
 1629         *mode =  le32toh(pCmd->Option);
 1630         *threshold = le32toh(pCmd->Threshold);
 1631         return retval;
 1632 }
 1633 
 1634 /*
 1635  * Set CFEND status Enable/Disable
 1636  */
 1637 int
 1638 mwl_hal_setcfend(struct mwl_hal *mh0, int ena)
 1639 {
 1640         struct mwl_hal_priv *mh = MWLPRIV(mh0);
 1641         HostCmd_CFEND_ENABLE *pCmd;
 1642         int retval;
 1643 
 1644         MWL_HAL_LOCK(mh);
 1645         _CMD_SETUP(pCmd, HostCmd_CFEND_ENABLE,
 1646                 HostCmd_CMD_CFEND_ENABLE);
 1647         pCmd->Enable = htole32(ena);
 1648 
 1649         retval = mwlExecuteCmd(mh, HostCmd_CMD_CFEND_ENABLE);
 1650         MWL_HAL_UNLOCK(mh); 
 1651         return retval;
 1652 }
 1653 
 1654 int
 1655 mwl_hal_setdwds(struct mwl_hal *mh0, int ena)
 1656 {
 1657         HostCmd_DWDS_ENABLE *pCmd;
 1658         struct mwl_hal_priv *mh = MWLPRIV(mh0);
 1659         int retval;
 1660 
 1661         MWL_HAL_LOCK(mh);
 1662         _CMD_SETUP(pCmd, HostCmd_DWDS_ENABLE, HostCmd_CMD_DWDS_ENABLE);
 1663         pCmd->Enable = htole32(ena);
 1664         retval = mwlExecuteCmd(mh, HostCmd_CMD_DWDS_ENABLE);
 1665         MWL_HAL_UNLOCK(mh);
 1666         return retval;
 1667 }
 1668 
 1669 static void
 1670 cvtPeerInfo(PeerInfo_t *to, const MWL_HAL_PEERINFO *from)
 1671 {
 1672         to->LegacyRateBitMap = htole32(from->LegacyRateBitMap);
 1673         to->HTRateBitMap = htole32(from->HTRateBitMap);
 1674         to->CapInfo = htole16(from->CapInfo);
 1675         to->HTCapabilitiesInfo = htole16(from->HTCapabilitiesInfo);
 1676         to->MacHTParamInfo = from->MacHTParamInfo;
 1677         to->AddHtInfo.ControlChan = from->AddHtInfo.ControlChan;
 1678         to->AddHtInfo.AddChan = from->AddHtInfo.AddChan;
 1679         to->AddHtInfo.OpMode = htole16(from->AddHtInfo.OpMode);
 1680         to->AddHtInfo.stbc = htole16(from->AddHtInfo.stbc);
 1681 }
 1682 
 1683 /* XXX station id must be in [0..63] */
 1684 int
 1685 mwl_hal_newstation(struct mwl_hal_vap *vap,
 1686         const uint8_t addr[IEEE80211_ADDR_LEN], uint16_t aid, uint16_t sid, 
 1687         const MWL_HAL_PEERINFO *peer, int isQosSta, int wmeInfo)
 1688 {
 1689         struct mwl_hal_priv *mh = MWLVAP(vap);
 1690         HostCmd_FW_SET_NEW_STN *pCmd;
 1691         int retval;
 1692 
 1693         MWL_HAL_LOCK(mh);
 1694         _VCMD_SETUP(vap, pCmd, HostCmd_FW_SET_NEW_STN, HostCmd_CMD_SET_NEW_STN);
 1695         pCmd->AID = htole16(aid);
 1696         pCmd->StnId = htole16(sid);
 1697         pCmd->Action = htole16(0);      /* SET */
 1698         if (peer != NULL) {
 1699                 /* NB: must fix up byte order */
 1700                 cvtPeerInfo(&pCmd->PeerInfo, peer);
 1701         }
 1702         IEEE80211_ADDR_COPY(&pCmd->MacAddr[0], addr);
 1703         pCmd->Qosinfo = wmeInfo;
 1704         pCmd->isQosSta = (isQosSta != 0);
 1705 
 1706         retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_NEW_STN);
 1707         if (retval == 0 && IEEE80211_ADDR_EQ(vap->mac, addr))
 1708                 vap->flags |= MVF_STATION;
 1709         MWL_HAL_UNLOCK(mh);
 1710         return retval;
 1711 }
 1712 
 1713 int
 1714 mwl_hal_delstation(struct mwl_hal_vap *vap,
 1715         const uint8_t addr[IEEE80211_ADDR_LEN])
 1716 {
 1717         struct mwl_hal_priv *mh = MWLVAP(vap);
 1718         HostCmd_FW_SET_NEW_STN *pCmd;
 1719         int retval, islocal;
 1720 
 1721         MWL_HAL_LOCK(mh);
 1722         islocal = IEEE80211_ADDR_EQ(vap->mac, addr);
 1723         if (!islocal || (vap->flags & MVF_STATION)) {
 1724                 _VCMD_SETUP(vap, pCmd, HostCmd_FW_SET_NEW_STN,
 1725                     HostCmd_CMD_SET_NEW_STN);
 1726                 pCmd->Action = htole16(2);      /* REMOVE */
 1727                 IEEE80211_ADDR_COPY(&pCmd->MacAddr[0], addr);
 1728                 retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_NEW_STN);
 1729                 if (islocal)
 1730                         vap->flags &= ~MVF_STATION;
 1731         } else
 1732                 retval = 0;
 1733         MWL_HAL_UNLOCK(mh);
 1734         return retval;
 1735 }
 1736 
 1737 /*
 1738  * Prod the firmware to age packets on station power
 1739  * save queues and reap frames on the tx aggregation q's.
 1740  */
 1741 int
 1742 mwl_hal_setkeepalive(struct mwl_hal *mh0)
 1743 {
 1744         struct mwl_hal_priv *mh = MWLPRIV(mh0);
 1745         HostCmd_FW_SET_KEEP_ALIVE_TICK *pCmd;
 1746         int retval;
 1747 
 1748         MWL_HAL_LOCK(mh);
 1749         _CMD_SETUP(pCmd, HostCmd_FW_SET_KEEP_ALIVE_TICK,
 1750                 HostCmd_CMD_SET_KEEP_ALIVE);
 1751         /*
 1752          * NB: tick must be 0 to prod the f/w;
 1753          *     a non-zero value is a noop.
 1754          */
 1755         pCmd->tick = 0;
 1756 
 1757         retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_KEEP_ALIVE);
 1758         MWL_HAL_UNLOCK(mh);
 1759         return retval;
 1760 }
 1761 
 1762 int
 1763 mwl_hal_setapmode(struct mwl_hal_vap *vap, MWL_HAL_APMODE ApMode)
 1764 {
 1765         struct mwl_hal_priv *mh = MWLVAP(vap);
 1766         HostCmd_FW_SET_APMODE *pCmd;
 1767         int retval;
 1768 
 1769         /* XXX validate ApMode? */
 1770 
 1771         MWL_HAL_LOCK(mh);
 1772         _VCMD_SETUP(vap, pCmd, HostCmd_FW_SET_APMODE, HostCmd_CMD_SET_APMODE);
 1773         pCmd->ApMode = ApMode;
 1774 
 1775         retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_APMODE);
 1776         MWL_HAL_UNLOCK(mh);
 1777         return retval;
 1778 }
 1779 
 1780 int
 1781 mwl_hal_stop(struct mwl_hal_vap *vap)
 1782 {
 1783         struct mwl_hal_priv *mh = MWLVAP(vap);
 1784         HostCmd_DS_BSS_START *pCmd;
 1785         int retval;
 1786 
 1787         MWL_HAL_LOCK(mh);
 1788         if (vap->flags & MVF_RUNNING) {
 1789                 _VCMD_SETUP(vap, pCmd, HostCmd_DS_BSS_START,
 1790                     HostCmd_CMD_BSS_START);
 1791                 pCmd->Enable = htole32(HostCmd_ACT_GEN_OFF);
 1792                 retval = mwlExecuteCmd(mh, HostCmd_CMD_BSS_START);
 1793         } else
 1794                 retval = 0;
 1795         /* NB: mark !running regardless */
 1796         vap->flags &= ~MVF_RUNNING;
 1797         MWL_HAL_UNLOCK(mh);
 1798         return retval;
 1799 }
 1800 
 1801 int
 1802 mwl_hal_start(struct mwl_hal_vap *vap)
 1803 {
 1804         struct mwl_hal_priv *mh = MWLVAP(vap);
 1805         HostCmd_DS_BSS_START *pCmd;
 1806         int retval;
 1807 
 1808         MWL_HAL_LOCK(mh);
 1809         _VCMD_SETUP(vap, pCmd, HostCmd_DS_BSS_START, HostCmd_CMD_BSS_START);
 1810         pCmd->Enable = htole32(HostCmd_ACT_GEN_ON);
 1811 
 1812         retval = mwlExecuteCmd(mh, HostCmd_CMD_BSS_START);
 1813         if (retval == 0)
 1814                 vap->flags |= MVF_RUNNING;
 1815         MWL_HAL_UNLOCK(mh);
 1816         return retval;
 1817 }
 1818 
 1819 int
 1820 mwl_hal_setgprot(struct mwl_hal *mh0, int prot)
 1821 {
 1822         struct mwl_hal_priv *mh = MWLPRIV(mh0);
 1823         HostCmd_FW_SET_G_PROTECT_FLAG *pCmd;
 1824         int retval;
 1825 
 1826         MWL_HAL_LOCK(mh);
 1827         _CMD_SETUP(pCmd, HostCmd_FW_SET_G_PROTECT_FLAG,
 1828                 HostCmd_CMD_SET_G_PROTECT_FLAG);
 1829         pCmd->GProtectFlag  = htole32(prot);
 1830 
 1831         retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_G_PROTECT_FLAG);
 1832         MWL_HAL_UNLOCK(mh);
 1833         return retval;
 1834 }
 1835 
 1836 int
 1837 mwl_hal_setwmm(struct mwl_hal *mh0, int onoff)
 1838 {
 1839         struct mwl_hal_priv *mh = MWLPRIV(mh0);
 1840         HostCmd_FW_SetWMMMode *pCmd;
 1841         int retval;
 1842 
 1843         MWL_HAL_LOCK(mh);
 1844         _CMD_SETUP(pCmd, HostCmd_FW_SetWMMMode,
 1845                 HostCmd_CMD_SET_WMM_MODE);
 1846         pCmd->Action = htole16(onoff);
 1847 
 1848         retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_WMM_MODE);
 1849         MWL_HAL_UNLOCK(mh);
 1850         return retval;
 1851 }
 1852 
 1853 int
 1854 mwl_hal_setedcaparams(struct mwl_hal *mh0, uint8_t qnum,
 1855         uint32_t CWmin, uint32_t CWmax, uint8_t AIFSN,  uint16_t TXOPLimit)
 1856 {
 1857         struct mwl_hal_priv *mh = MWLPRIV(mh0);
 1858         HostCmd_FW_SET_EDCA_PARAMS *pCmd;
 1859         int retval;
 1860 
 1861         MWL_HAL_LOCK(mh);
 1862         _CMD_SETUP(pCmd, HostCmd_FW_SET_EDCA_PARAMS,
 1863                 HostCmd_CMD_SET_EDCA_PARAMS);
 1864         /*
 1865          * NB: CWmin and CWmax are always set.
 1866          *     TxOpLimit is set if bit 0x2 is marked in Action
 1867          *     AIFSN is set if bit 0x4 is marked in Action
 1868          */
 1869         pCmd->Action = htole16(0xffff); /* NB: set everything */
 1870         pCmd->TxOP = htole16(TXOPLimit);
 1871         pCmd->CWMax = htole32(CWmax);
 1872         pCmd->CWMin = htole32(CWmin);
 1873         pCmd->AIFSN = AIFSN;
 1874         pCmd->TxQNum = qnum;            /* XXX check */
 1875 
 1876         retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_EDCA_PARAMS);
 1877         MWL_HAL_UNLOCK(mh);
 1878         return retval;
 1879 }
 1880 
 1881 /* XXX 0 = indoor, 1 = outdoor */
 1882 int
 1883 mwl_hal_setrateadaptmode(struct mwl_hal *mh0, uint16_t mode)
 1884 {
 1885         struct mwl_hal_priv *mh = MWLPRIV(mh0);
 1886         HostCmd_DS_SET_RATE_ADAPT_MODE *pCmd;
 1887         int retval;
 1888 
 1889         MWL_HAL_LOCK(mh);
 1890         _CMD_SETUP(pCmd, HostCmd_DS_SET_RATE_ADAPT_MODE,
 1891                 HostCmd_CMD_SET_RATE_ADAPT_MODE);
 1892         pCmd->Action = htole16(HostCmd_ACT_GEN_SET);
 1893         pCmd->RateAdaptMode = htole16(mode);
 1894 
 1895         retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_RATE_ADAPT_MODE);
 1896         MWL_HAL_UNLOCK(mh);
 1897         return retval;
 1898 }
 1899 
 1900 int
 1901 mwl_hal_setcsmode(struct mwl_hal *mh0, MWL_HAL_CSMODE csmode)
 1902 {
 1903         struct mwl_hal_priv *mh = MWLPRIV(mh0);
 1904         HostCmd_DS_SET_LINKADAPT_CS_MODE *pCmd;
 1905         int retval;
 1906 
 1907         MWL_HAL_LOCK(mh);
 1908         _CMD_SETUP(pCmd, HostCmd_DS_SET_LINKADAPT_CS_MODE,
 1909                 HostCmd_CMD_SET_LINKADAPT_CS_MODE);
 1910         pCmd->Action = htole16(HostCmd_ACT_GEN_SET);
 1911         pCmd->CSMode = htole16(csmode);
 1912 
 1913         retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_LINKADAPT_CS_MODE);
 1914         MWL_HAL_UNLOCK(mh);
 1915         return retval;
 1916 }
 1917 
 1918 int
 1919 mwl_hal_setnprot(struct mwl_hal_vap *vap, MWL_HAL_HTPROTECT mode)
 1920 {
 1921         struct mwl_hal_priv *mh = MWLVAP(vap);
 1922         HostCmd_FW_SET_N_PROTECT_FLAG *pCmd;
 1923         int retval;
 1924 
 1925         /* XXX validate mode */
 1926         MWL_HAL_LOCK(mh);
 1927         _VCMD_SETUP(vap, pCmd, HostCmd_FW_SET_N_PROTECT_FLAG,
 1928                 HostCmd_CMD_SET_N_PROTECT_FLAG);
 1929         pCmd->NProtectFlag  = htole32(mode);
 1930 
 1931         retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_N_PROTECT_FLAG);
 1932         MWL_HAL_UNLOCK(mh);
 1933         return retval;
 1934 }
 1935 
 1936 int
 1937 mwl_hal_setnprotmode(struct mwl_hal_vap *vap, uint8_t mode)
 1938 {
 1939         struct mwl_hal_priv *mh = MWLVAP(vap);
 1940         HostCmd_FW_SET_N_PROTECT_OPMODE *pCmd;
 1941         int retval;
 1942 
 1943         MWL_HAL_LOCK(mh);
 1944         _VCMD_SETUP(vap, pCmd, HostCmd_FW_SET_N_PROTECT_OPMODE,
 1945                 HostCmd_CMD_SET_N_PROTECT_OPMODE);
 1946         pCmd->NProtectOpMode = mode;
 1947 
 1948         retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_N_PROTECT_OPMODE);
 1949         MWL_HAL_UNLOCK(mh);
 1950         return retval;
 1951 }
 1952 
 1953 int
 1954 mwl_hal_setoptimizationlevel(struct mwl_hal *mh0, int level)
 1955 {
 1956         struct mwl_hal_priv *mh = MWLPRIV(mh0);
 1957         HostCmd_FW_SET_OPTIMIZATION_LEVEL *pCmd;
 1958         int retval;
 1959 
 1960         MWL_HAL_LOCK(mh);
 1961         _CMD_SETUP(pCmd, HostCmd_FW_SET_OPTIMIZATION_LEVEL,
 1962                 HostCmd_CMD_SET_OPTIMIZATION_LEVEL);
 1963         pCmd->OptLevel = level;
 1964 
 1965         retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_OPTIMIZATION_LEVEL);
 1966         MWL_HAL_UNLOCK(mh);
 1967         return retval;
 1968 }
 1969 
 1970 int
 1971 mwl_hal_setmimops(struct mwl_hal *mh0, const uint8_t addr[IEEE80211_ADDR_LEN],
 1972         uint8_t enable, uint8_t mode)
 1973 {
 1974         struct mwl_hal_priv *mh = MWLPRIV(mh0);
 1975         HostCmd_FW_SET_MIMOPSHT *pCmd;
 1976         int retval;
 1977 
 1978         MWL_HAL_LOCK(mh);
 1979         _CMD_SETUP(pCmd, HostCmd_FW_SET_MIMOPSHT, HostCmd_CMD_SET_MIMOPSHT);
 1980         IEEE80211_ADDR_COPY(pCmd->Addr, addr);
 1981         pCmd->Enable = enable;
 1982         pCmd->Mode = mode;
 1983 
 1984         retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_MIMOPSHT);
 1985         MWL_HAL_UNLOCK(mh);
 1986         return retval;
 1987 }
 1988 
 1989 static int
 1990 mwlGetCalTable(struct mwl_hal_priv *mh, uint8_t annex, uint8_t index)
 1991 {
 1992         HostCmd_FW_GET_CALTABLE *pCmd;
 1993         int retval;
 1994 
 1995         MWL_HAL_LOCK_ASSERT(mh);
 1996 
 1997         _CMD_SETUP(pCmd, HostCmd_FW_GET_CALTABLE, HostCmd_CMD_GET_CALTABLE);
 1998         pCmd->annex = annex;
 1999         pCmd->index = index;
 2000         memset(pCmd->calTbl, 0, sizeof(pCmd->calTbl));
 2001 
 2002         retval = mwlExecuteCmd(mh, HostCmd_CMD_GET_CALTABLE);
 2003         if (retval == 0 &&
 2004             pCmd->calTbl[0] != annex && annex != 0 && annex != 255)
 2005                 retval = EIO;
 2006         return retval;
 2007 }                                                         
 2008 
 2009 /*
 2010  * Calculate the max tx power from the channel's cal data.
 2011  */
 2012 static void
 2013 setmaxtxpow(struct mwl_hal_channel *hc, int i, int maxix)
 2014 {
 2015         hc->maxTxPow = hc->targetPowers[i];
 2016         for (i++; i < maxix; i++)
 2017                 if (hc->targetPowers[i] > hc->maxTxPow)
 2018                         hc->maxTxPow = hc->targetPowers[i];
 2019 }
 2020 
 2021 /*
 2022  * Construct channel info for 5GHz channels from cal data.
 2023  */
 2024 static void
 2025 get5Ghz(MWL_HAL_CHANNELINFO *ci, const uint8_t table[], int len)
 2026 {
 2027         int i, j, f, l, h;
 2028 
 2029         l = 32000;
 2030         h = 0;
 2031         j = 0;
 2032         for (i = 0; i < len; i += 4) {
 2033                 struct mwl_hal_channel *hc;
 2034 
 2035                 if (table[i] == 0)
 2036                         continue;
 2037                 f = 5000 + 5*table[i];
 2038                 if (f < l)
 2039                         l = f;
 2040                 if (f > h)
 2041                         h = f;
 2042                 hc = &ci->channels[j];
 2043                 hc->freq = f;
 2044                 hc->ieee = table[i];
 2045                 memcpy(hc->targetPowers, &table[i], 4);
 2046                 setmaxtxpow(hc, 1, 4);          /* NB: col 1 is the freq, skip*/
 2047                 j++;
 2048         }
 2049         ci->nchannels = j;
 2050         ci->freqLow = (l == 32000) ? 0 : l;
 2051         ci->freqHigh = h;
 2052 }
 2053 
 2054 static uint16_t
 2055 ieee2mhz(int chan)
 2056 {
 2057         if (chan == 14)
 2058                 return 2484;
 2059         if (chan < 14)
 2060                 return 2407 + chan*5;
 2061         return 2512 + (chan-15)*20;
 2062 }
 2063 
 2064 /*
 2065  * Construct channel info for 2.4GHz channels from cal data.
 2066  */
 2067 static void
 2068 get2Ghz(MWL_HAL_CHANNELINFO *ci, const uint8_t table[], int len)
 2069 {
 2070         int i, j;
 2071 
 2072         j = 0;
 2073         for (i = 0; i < len; i += 4) {
 2074                 struct mwl_hal_channel *hc = &ci->channels[j];
 2075                 hc->ieee = 1+j;
 2076                 hc->freq = ieee2mhz(1+j);
 2077                 memcpy(hc->targetPowers, &table[i], 4);
 2078                 setmaxtxpow(hc, 0, 4);
 2079                 j++;
 2080         }
 2081         ci->nchannels = j;
 2082         ci->freqLow = ieee2mhz(1);
 2083         ci->freqHigh = ieee2mhz(j);
 2084 }
 2085 
 2086 #undef DUMPCALDATA
 2087 #ifdef DUMPCALDATA
 2088 static void
 2089 dumpcaldata(const char *name, const uint8_t *table, int n)
 2090 {
 2091         int i;
 2092         printf("\n%s:\n", name);
 2093         for (i = 0; i < n; i += 4)
 2094                 printf("[%2d] %3d %3d %3d %3d\n", i/4, table[i+0], table[i+1], table[i+2], table[i+3]);
 2095 }
 2096 #endif
 2097 
 2098 static int
 2099 mwlGetPwrCalTable(struct mwl_hal_priv *mh)
 2100 {
 2101         const uint8_t *data;
 2102         MWL_HAL_CHANNELINFO *ci;
 2103         int len;
 2104 
 2105         MWL_HAL_LOCK(mh);
 2106         /* NB: we hold the lock so it's ok to use cmdbuf */
 2107         data = ((const HostCmd_FW_GET_CALTABLE *) mh->mh_cmdbuf)->calTbl;
 2108         if (mwlGetCalTable(mh, 33, 0) == 0) {
 2109                 len = (data[2] | (data[3] << 8)) - 12;
 2110                 if (len > PWTAGETRATETABLE20M)
 2111                         len = PWTAGETRATETABLE20M;
 2112 #ifdef DUMPCALDATA
 2113 dumpcaldata("2.4G 20M", &data[12], len);/*XXX*/
 2114 #endif
 2115                 get2Ghz(&mh->mh_20M, &data[12], len);
 2116         }
 2117         if (mwlGetCalTable(mh, 34, 0) == 0) {
 2118                 len = (data[2] | (data[3] << 8)) - 12;
 2119                 if (len > PWTAGETRATETABLE40M)
 2120                         len = PWTAGETRATETABLE40M;
 2121 #ifdef DUMPCALDATA
 2122 dumpcaldata("2.4G 40M", &data[12], len);/*XXX*/
 2123 #endif
 2124                 ci = &mh->mh_40M;
 2125                 get2Ghz(ci, &data[12], len);
 2126         }
 2127         if (mwlGetCalTable(mh, 35, 0) == 0) {
 2128                 len = (data[2] | (data[3] << 8)) - 20;
 2129                 if (len > PWTAGETRATETABLE20M_5G)
 2130                         len = PWTAGETRATETABLE20M_5G;
 2131 #ifdef DUMPCALDATA
 2132 dumpcaldata("5G 20M", &data[20], len);/*XXX*/
 2133 #endif
 2134                 get5Ghz(&mh->mh_20M_5G, &data[20], len);
 2135         }
 2136         if (mwlGetCalTable(mh, 36, 0) == 0) {
 2137                 len = (data[2] | (data[3] << 8)) - 20;
 2138                 if (len > PWTAGETRATETABLE40M_5G)
 2139                         len = PWTAGETRATETABLE40M_5G;
 2140 #ifdef DUMPCALDATA
 2141 dumpcaldata("5G 40M", &data[20], len);/*XXX*/
 2142 #endif
 2143                 ci = &mh->mh_40M_5G;
 2144                 get5Ghz(ci, &data[20], len);
 2145         }
 2146         mh->mh_flags |= MHF_CALDATA;
 2147         MWL_HAL_UNLOCK(mh);
 2148         return 0;
 2149 }
 2150 
 2151 int
 2152 mwl_hal_getregioncode(struct mwl_hal *mh0, uint8_t *countryCode)
 2153 {
 2154         struct mwl_hal_priv *mh = MWLPRIV(mh0);
 2155         int retval;
 2156 
 2157         MWL_HAL_LOCK(mh);
 2158         retval = mwlGetCalTable(mh, 0, 0);
 2159         if (retval == 0) {
 2160                 const HostCmd_FW_GET_CALTABLE *pCmd =
 2161                     (const HostCmd_FW_GET_CALTABLE *) mh->mh_cmdbuf;
 2162                 *countryCode = pCmd->calTbl[16];
 2163         }
 2164         MWL_HAL_UNLOCK(mh);
 2165         return retval;
 2166 }
 2167 
 2168 int
 2169 mwl_hal_setpromisc(struct mwl_hal *mh0, int ena)
 2170 {
 2171         struct mwl_hal_priv *mh = MWLPRIV(mh0);
 2172         uint32_t v;
 2173 
 2174         MWL_HAL_LOCK(mh);
 2175         v = RD4(mh, MACREG_REG_PROMISCUOUS);
 2176         WR4(mh, MACREG_REG_PROMISCUOUS, ena ? v | 1 : v &~ 1);
 2177         MWL_HAL_UNLOCK(mh);
 2178         return 0;
 2179 }
 2180 
 2181 int
 2182 mwl_hal_getpromisc(struct mwl_hal *mh0)
 2183 {
 2184         struct mwl_hal_priv *mh = MWLPRIV(mh0);
 2185         uint32_t v;
 2186 
 2187         MWL_HAL_LOCK(mh);
 2188         v = RD4(mh, MACREG_REG_PROMISCUOUS);
 2189         MWL_HAL_UNLOCK(mh);
 2190         return (v & 1) != 0;
 2191 }
 2192 
 2193 int
 2194 mwl_hal_GetBeacon(struct mwl_hal *mh0, uint8_t *pBcn, uint16_t *pLen)
 2195 {
 2196         struct mwl_hal_priv *mh = MWLPRIV(mh0);
 2197         HostCmd_FW_GET_BEACON *pCmd;
 2198         int retval;
 2199 
 2200         MWL_HAL_LOCK(mh);
 2201         _CMD_SETUP(pCmd, HostCmd_FW_GET_BEACON, HostCmd_CMD_GET_BEACON);
 2202         pCmd->Bcnlen = htole16(0);
 2203 
 2204         retval = mwlExecuteCmd(mh, HostCmd_CMD_GET_BEACON);
 2205         if (retval == 0) {
 2206                 /* XXX bounds check */
 2207                 memcpy(pBcn, &pCmd->Bcn, pCmd->Bcnlen);
 2208                 *pLen = pCmd->Bcnlen;
 2209         }
 2210         MWL_HAL_UNLOCK(mh);
 2211         return retval;
 2212 }       
 2213 
 2214 int
 2215 mwl_hal_SetRifs(struct mwl_hal *mh0, uint8_t QNum)
 2216 {
 2217         struct mwl_hal_priv *mh = MWLPRIV(mh0);
 2218         HostCmd_FW_SET_RIFS  *pCmd;
 2219         int retval;
 2220 
 2221         MWL_HAL_LOCK(mh);
 2222         _CMD_SETUP(pCmd, HostCmd_FW_SET_RIFS, HostCmd_CMD_SET_RIFS);
 2223         pCmd->QNum = QNum;
 2224 
 2225         retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_RIFS);
 2226         MWL_HAL_UNLOCK(mh);
 2227         return retval;
 2228 }
 2229 
 2230 /*
 2231  * Diagnostic api's for set/get registers.
 2232  */
 2233 
 2234 static int
 2235 getRFReg(struct mwl_hal_priv *mh, int flag, uint32_t reg, uint32_t *val)
 2236 {
 2237         HostCmd_DS_RF_REG_ACCESS *pCmd;
 2238         int retval;
 2239 
 2240         MWL_HAL_LOCK(mh);
 2241         _CMD_SETUP(pCmd, HostCmd_DS_RF_REG_ACCESS, HostCmd_CMD_RF_REG_ACCESS);
 2242         pCmd->Offset =  htole16(reg);
 2243         pCmd->Action = htole16(flag);
 2244         pCmd->Value = htole32(*val);
 2245 
 2246         retval = mwlExecuteCmd(mh, HostCmd_CMD_RF_REG_ACCESS);
 2247         if (retval == 0)
 2248                 *val = pCmd->Value;
 2249         MWL_HAL_UNLOCK(mh);
 2250         return retval;
 2251 }
 2252 
 2253 static int
 2254 getBBReg(struct mwl_hal_priv *mh, int flag, uint32_t reg, uint32_t *val)
 2255 {
 2256         HostCmd_DS_BBP_REG_ACCESS *pCmd;
 2257         int retval;
 2258 
 2259         MWL_HAL_LOCK(mh);
 2260         _CMD_SETUP(pCmd, HostCmd_DS_BBP_REG_ACCESS, HostCmd_CMD_BBP_REG_ACCESS);
 2261         pCmd->Offset =  htole16(reg);
 2262         pCmd->Action = htole16(flag);
 2263         pCmd->Value = htole32(*val);
 2264 
 2265         retval = mwlExecuteCmd(mh, HostCmd_CMD_BBP_REG_ACCESS);
 2266         if (retval == 0)
 2267                 *val = pCmd->Value;
 2268         MWL_HAL_UNLOCK(mh);
 2269         return retval;
 2270 }
 2271 
 2272 static u_int
 2273 mwl_hal_getregdump(struct mwl_hal_priv *mh, const MWL_DIAG_REGRANGE *regs,
 2274         void *dstbuf, int space)
 2275 {
 2276         uint32_t *dp = dstbuf;
 2277         int i;
 2278 
 2279         for (i = 0; space >= 2*sizeof(uint32_t); i++) {
 2280                 u_int r = regs[i].start;
 2281                 u_int e = regs[i].end;
 2282                 *dp++ = (r<<16) | e;
 2283                 space -= sizeof(uint32_t);
 2284                 do {
 2285                         if (MWL_DIAG_ISMAC(r))
 2286                                 *dp = RD4(mh, r);
 2287                         else if (MWL_DIAG_ISBB(r))
 2288                                 getBBReg(mh, HostCmd_ACT_GEN_READ,
 2289                                     r - MWL_DIAG_BASE_BB, dp);
 2290                         else if (MWL_DIAG_ISRF(r))
 2291                                 getRFReg(mh, HostCmd_ACT_GEN_READ,
 2292                                     r - MWL_DIAG_BASE_RF, dp);
 2293                         else if (r < 0x1000 || r == MACREG_REG_FW_PRESENT)
 2294                                 *dp = RD4(mh, r);
 2295                         else
 2296                                 *dp = 0xffffffff;
 2297                         dp++;
 2298                         r += sizeof(uint32_t);
 2299                         space -= sizeof(uint32_t);
 2300                 } while (r <= e && space >= sizeof(uint32_t));
 2301         }
 2302         return (char *) dp - (char *) dstbuf;
 2303 }
 2304 
 2305 int
 2306 mwl_hal_getdiagstate(struct mwl_hal *mh0, int request,
 2307         const void *args, uint32_t argsize,
 2308         void **result, uint32_t *resultsize)
 2309 {
 2310         struct mwl_hal_priv *mh = MWLPRIV(mh0);
 2311 
 2312         switch (request) {
 2313         case MWL_DIAG_CMD_REVS:
 2314                 *result = &mh->mh_revs;
 2315                 *resultsize = sizeof(mh->mh_revs);
 2316                 return 1;
 2317         case MWL_DIAG_CMD_REGS:
 2318                 *resultsize = mwl_hal_getregdump(mh, args, *result, *resultsize);
 2319                 return 1;
 2320         case MWL_DIAG_CMD_HOSTCMD: {
 2321                 FWCmdHdr *pCmd = (FWCmdHdr *) &mh->mh_cmdbuf[0];
 2322                 int retval;
 2323 
 2324                 MWL_HAL_LOCK(mh);
 2325                 memcpy(pCmd, args, argsize);
 2326                 retval = mwlExecuteCmd(mh, le16toh(pCmd->Cmd));
 2327                 *result = (*resultsize != 0) ? pCmd : NULL;
 2328                 MWL_HAL_UNLOCK(mh);
 2329                 return (retval == 0);
 2330         }
 2331         case MWL_DIAG_CMD_FWLOAD:
 2332                 if (mwl_hal_fwload(mh0, __DECONST(void *, args))) {
 2333                         device_printf(mh->mh_dev, "problem loading fw image\n");
 2334                         return 0;
 2335                 }
 2336                 return 1;
 2337         }
 2338         return 0;
 2339 }
 2340 
 2341 /*
 2342  * Low level firmware cmd block handshake support.
 2343  */
 2344 
 2345 static void
 2346 mwlSendCmd(struct mwl_hal_priv *mh)
 2347 {
 2348 
 2349         bus_dmamap_sync(mh->mh_dmat, mh->mh_dmamap,
 2350             BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
 2351 
 2352         WR4(mh, MACREG_REG_GEN_PTR, mh->mh_cmdaddr);
 2353         RD4(mh, MACREG_REG_INT_CODE);
 2354 
 2355         WR4(mh, MACREG_REG_H2A_INTERRUPT_EVENTS, MACREG_H2ARIC_BIT_DOOR_BELL);
 2356 }
 2357 
 2358 static int
 2359 mwlWaitForCmdComplete(struct mwl_hal_priv *mh, uint16_t cmdCode)
 2360 {
 2361 #define MAX_WAIT_FW_COMPLETE_ITERATIONS 10000
 2362         int i;
 2363 
 2364         for (i = 0; i < MAX_WAIT_FW_COMPLETE_ITERATIONS; i++) {
 2365                 if (mh->mh_cmdbuf[0] == le16toh(cmdCode))
 2366                         return 1;
 2367                 DELAY(1*1000);
 2368         }
 2369         return 0;
 2370 #undef MAX_WAIT_FW_COMPLETE_ITERATIONS
 2371 }
 2372 
 2373 static int
 2374 mwlExecuteCmd(struct mwl_hal_priv *mh, unsigned short cmd)
 2375 {
 2376 
 2377         MWL_HAL_LOCK_ASSERT(mh);
 2378 
 2379         if ((mh->mh_flags & MHF_FWHANG) &&
 2380             (mh->mh_debug & MWL_HAL_DEBUG_IGNHANG) == 0) {
 2381 #ifdef MWLHAL_DEBUG
 2382                 device_printf(mh->mh_dev, "firmware hung, skipping cmd %s\n",
 2383                         mwlcmdname(cmd));
 2384 #else
 2385                 device_printf(mh->mh_dev, "firmware hung, skipping cmd 0x%x\n",
 2386                         cmd);
 2387 #endif
 2388                 return ENXIO;
 2389         }
 2390         if (RD4(mh,  MACREG_REG_INT_CODE) == 0xffffffff) {
 2391                 device_printf(mh->mh_dev, "%s: device not present!\n",
 2392                     __func__);
 2393                 return EIO;
 2394         }
 2395 #ifdef MWLHAL_DEBUG
 2396         if (mh->mh_debug & MWL_HAL_DEBUG_SENDCMD)
 2397                 dumpresult(mh, 0);
 2398 #endif
 2399         mwlSendCmd(mh);
 2400         if (!mwlWaitForCmdComplete(mh, 0x8000 | cmd)) {
 2401 #ifdef MWLHAL_DEBUG
 2402                 device_printf(mh->mh_dev,
 2403                     "timeout waiting for f/w cmd %s\n", mwlcmdname(cmd));
 2404 #else
 2405                 device_printf(mh->mh_dev,
 2406                     "timeout waiting for f/w cmd 0x%x\n", cmd);
 2407 #endif
 2408                 mh->mh_flags |= MHF_FWHANG;
 2409                 return ETIMEDOUT;
 2410         }
 2411         bus_dmamap_sync(mh->mh_dmat, mh->mh_dmamap,
 2412             BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
 2413 #ifdef MWLHAL_DEBUG
 2414         if (mh->mh_debug & MWL_HAL_DEBUG_CMDDONE)
 2415                 dumpresult(mh, 1);
 2416 #endif
 2417         return 0;
 2418 }
 2419 
 2420 /*
 2421  * Firmware download support.
 2422  */
 2423 #define FW_DOWNLOAD_BLOCK_SIZE  256  
 2424 #define FW_CHECK_USECS          (5*1000)        /* 5ms */
 2425 #define FW_MAX_NUM_CHECKS       200  
 2426 
 2427 #if 0
 2428 /* XXX read f/w from file */
 2429 #include <dev/mwl/mwlbootfw.h>
 2430 #include <dev/mwl/mwl88W8363fw.h>
 2431 #endif
 2432 
 2433 static void
 2434 mwlFwReset(struct mwl_hal_priv *mh)
 2435 {
 2436         if (RD4(mh,  MACREG_REG_INT_CODE) == 0xffffffff) {
 2437                 device_printf(mh->mh_dev, "%s: device not present!\n",
 2438                     __func__);
 2439                 return;
 2440         }
 2441         WR4(mh, MACREG_REG_H2A_INTERRUPT_EVENTS, ISR_RESET);
 2442         mh->mh_flags &= ~MHF_FWHANG;
 2443 }
 2444 
 2445 static void
 2446 mwlTriggerPciCmd(struct mwl_hal_priv *mh)
 2447 {
 2448 
 2449         bus_dmamap_sync(mh->mh_dmat, mh->mh_dmamap, BUS_DMASYNC_PREWRITE);
 2450 
 2451         WR4(mh, MACREG_REG_GEN_PTR, mh->mh_cmdaddr);
 2452         RD4(mh, MACREG_REG_INT_CODE);
 2453 
 2454         WR4(mh, MACREG_REG_INT_CODE, 0x00);
 2455         RD4(mh, MACREG_REG_INT_CODE);
 2456 
 2457         WR4(mh, MACREG_REG_H2A_INTERRUPT_EVENTS, MACREG_H2ARIC_BIT_DOOR_BELL);
 2458         RD4(mh, MACREG_REG_INT_CODE);
 2459 }
 2460 
 2461 static int
 2462 mwlWaitFor(struct mwl_hal_priv *mh, uint32_t val)
 2463 {
 2464         int i;
 2465 
 2466         for (i = 0; i < FW_MAX_NUM_CHECKS; i++) {
 2467                 DELAY(FW_CHECK_USECS);
 2468                 if (RD4(mh, MACREG_REG_INT_CODE) == val)
 2469                         return 1;
 2470         }
 2471         return 0;
 2472 }
 2473 
 2474 /*
 2475  * Firmware block xmit when talking to the boot-rom.
 2476  */
 2477 static int
 2478 mwlSendBlock(struct mwl_hal_priv *mh, int bsize, const void *data, size_t dsize)
 2479 {
 2480         mh->mh_cmdbuf[0] = htole16(HostCmd_CMD_CODE_DNLD);
 2481         mh->mh_cmdbuf[1] = htole16(bsize);
 2482         memcpy(&mh->mh_cmdbuf[4], data , dsize);
 2483         mwlTriggerPciCmd(mh);
 2484         /* XXX 2000 vs 200 */
 2485         if (mwlWaitFor(mh, MACREG_INT_CODE_CMD_FINISHED)) {
 2486                 WR4(mh, MACREG_REG_INT_CODE, 0);
 2487                 return 1;
 2488         }
 2489         device_printf(mh->mh_dev,
 2490             "%s: timeout waiting for CMD_FINISHED, INT_CODE 0x%x\n",
 2491             __func__, RD4(mh, MACREG_REG_INT_CODE));
 2492         return 0;
 2493 }
 2494 
 2495 /*
 2496  * Firmware block xmit when talking to the 1st-stage loader.
 2497  */
 2498 static int
 2499 mwlSendBlock2(struct mwl_hal_priv *mh, const void *data, size_t dsize)
 2500 {
 2501         memcpy(&mh->mh_cmdbuf[0], data, dsize);
 2502         mwlTriggerPciCmd(mh);
 2503         if (mwlWaitFor(mh, MACREG_INT_CODE_CMD_FINISHED)) {
 2504                 WR4(mh, MACREG_REG_INT_CODE, 0);
 2505                 return 1;
 2506         }
 2507         device_printf(mh->mh_dev,
 2508             "%s: timeout waiting for CMD_FINISHED, INT_CODE 0x%x\n",
 2509             __func__, RD4(mh, MACREG_REG_INT_CODE));
 2510         return 0;
 2511 }
 2512 
 2513 static void
 2514 mwlPokeSdramController(struct mwl_hal_priv *mh, int SDRAMSIZE_Addr)
 2515 {
 2516         /** Set up sdram controller for superflyv2 **/
 2517         WR4(mh, 0x00006014, 0x33);
 2518         WR4(mh, 0x00006018, 0xa3a2632);
 2519         WR4(mh, 0x00006010, SDRAMSIZE_Addr);
 2520 }
 2521 
 2522 int
 2523 mwl_hal_fwload(struct mwl_hal *mh0, void *fwargs)
 2524 {
 2525         struct mwl_hal_priv *mh = MWLPRIV(mh0);
 2526         const char *fwname = "mw88W8363fw";
 2527         const char *fwbootname = "mwlboot";
 2528         const struct firmware *fwboot = NULL;
 2529         const struct firmware *fw;
 2530         /* XXX get from firmware header */
 2531         uint32_t FwReadySignature = HostCmd_SOFTAP_FWRDY_SIGNATURE;
 2532         uint32_t OpMode = HostCmd_SOFTAP_MODE;
 2533         const uint8_t *fp, *ep;
 2534         const uint8_t *fmdata;
 2535         uint32_t blocksize, nbytes, fmsize;
 2536         int i, error, ntries;
 2537 
 2538         fw = firmware_get(fwname);
 2539         if (fw == NULL) {
 2540                 device_printf(mh->mh_dev,
 2541                     "could not load firmware image %s\n", fwname);
 2542                 return ENXIO;
 2543         }
 2544         fmdata = fw->data;
 2545         fmsize = fw->datasize;
 2546         if (fmsize < 4) {
 2547                 device_printf(mh->mh_dev, "firmware image %s too small\n",
 2548                     fwname);
 2549                 error = ENXIO;
 2550                 goto bad2;
 2551         }
 2552         if (fmdata[0] == 0x01 && fmdata[1] == 0x00 &&
 2553             fmdata[2] == 0x00 && fmdata[3] == 0x00) {
 2554                 /*
 2555                  * 2-stage load, get the boot firmware.
 2556                  */
 2557                 fwboot = firmware_get(fwbootname);
 2558                 if (fwboot == NULL) {
 2559                         device_printf(mh->mh_dev,
 2560                             "could not load firmware image %s\n", fwbootname);
 2561                         error = ENXIO;
 2562                         goto bad2;
 2563                 }
 2564         } else
 2565                 fwboot = NULL;
 2566 
 2567         mwlFwReset(mh);
 2568 
 2569         WR4(mh, MACREG_REG_A2H_INTERRUPT_CLEAR_SEL, MACREG_A2HRIC_BIT_MASK);
 2570         WR4(mh, MACREG_REG_A2H_INTERRUPT_CAUSE, 0x00);
 2571         WR4(mh, MACREG_REG_A2H_INTERRUPT_MASK, 0x00);
 2572         WR4(mh, MACREG_REG_A2H_INTERRUPT_STATUS_MASK, MACREG_A2HRIC_BIT_MASK);
 2573         if (mh->mh_SDRAMSIZE_Addr != 0) {
 2574                 /** Set up sdram controller for superflyv2 **/
 2575                 mwlPokeSdramController(mh, mh->mh_SDRAMSIZE_Addr);
 2576         }
 2577         device_printf(mh->mh_dev, "load %s firmware image (%u bytes)\n",
 2578             fwname, fmsize);
 2579         if (fwboot != NULL) {
 2580                 /*
 2581                  * Do 2-stage load.  The 1st stage loader is setup
 2582                  * with the bootrom loader then we load the real
 2583                  * image using a different handshake. With this
 2584                  * mechanism the firmware is segmented into chunks
 2585                  * that have a CRC.  If a chunk is incorrect we'll
 2586                  * be told to retransmit.
 2587                  */
 2588                 /* XXX assumes hlpimage fits in a block */
 2589                 /* NB: zero size block indicates download is finished */
 2590                 if (!mwlSendBlock(mh, fwboot->datasize, fwboot->data, fwboot->datasize) ||
 2591                     !mwlSendBlock(mh, 0, NULL, 0)) {
 2592                         error = ETIMEDOUT;
 2593                         goto bad;
 2594                 }
 2595                 DELAY(200*FW_CHECK_USECS);
 2596                 if (mh->mh_SDRAMSIZE_Addr != 0) {
 2597                         /** Set up sdram controller for superflyv2 **/
 2598                         mwlPokeSdramController(mh, mh->mh_SDRAMSIZE_Addr);
 2599                 }
 2600                 nbytes = ntries = 0;            /* NB: silence compiler */
 2601                 for (fp = fmdata, ep = fp + fmsize; fp < ep; ) {
 2602                         WR4(mh, MACREG_REG_INT_CODE, 0);
 2603                         blocksize = RD4(mh, MACREG_REG_SCRATCH);
 2604                         if (blocksize == 0)     /* download complete */
 2605                                 break;
 2606                         if (blocksize > 0x00000c00) {
 2607                                 error = EINVAL;
 2608                                 goto bad;
 2609                         }
 2610                         if ((blocksize & 0x1) == 0) {
 2611                                 /* block successfully downloaded, advance */
 2612                                 fp += nbytes;
 2613                                 ntries = 0;
 2614                         } else {
 2615                                 if (++ntries > 2) {
 2616                                         /*
 2617                                          * Guard against f/w telling us to
 2618                                          * retry infinitely.
 2619                                          */
 2620                                         error = ELOOP;
 2621                                         goto bad;
 2622                                 }
 2623                                 /* clear NAK bit/flag */
 2624                                 blocksize &= ~0x1;
 2625                         }
 2626                         if (blocksize > ep - fp) {
 2627                                 /* XXX this should not happen, what to do? */
 2628                                 blocksize = ep - fp;
 2629                         }
 2630                         nbytes = blocksize;
 2631                         if (!mwlSendBlock2(mh, fp, nbytes)) {
 2632                                 error = ETIMEDOUT;
 2633                                 goto bad;
 2634                         }
 2635                 }
 2636         } else {
 2637                 for (fp = fmdata, ep = fp + fmsize; fp < ep;) {
 2638                         nbytes = ep - fp;
 2639                         if (nbytes > FW_DOWNLOAD_BLOCK_SIZE)
 2640                                 nbytes = FW_DOWNLOAD_BLOCK_SIZE;
 2641                         if (!mwlSendBlock(mh, FW_DOWNLOAD_BLOCK_SIZE, fp, nbytes)) {
 2642                                 error = EIO;
 2643                                 goto bad;
 2644                         }
 2645                         fp += nbytes;
 2646                 }
 2647         }
 2648         /* done with firmware... */
 2649         if (fwboot != NULL)
 2650                 firmware_put(fwboot, FIRMWARE_UNLOAD);
 2651         firmware_put(fw, FIRMWARE_UNLOAD);
 2652         /*
 2653          * Wait for firmware to startup; we monitor the
 2654          * INT_CODE register waiting for a signature to
 2655          * written back indicating it's ready to go.
 2656          */
 2657         mh->mh_cmdbuf[1] = 0;
 2658         /*
 2659          * XXX WAR for mfg fw download
 2660          */
 2661         if (OpMode != HostCmd_STA_MODE)
 2662                 mwlTriggerPciCmd(mh);
 2663         for (i = 0; i < FW_MAX_NUM_CHECKS; i++) {
 2664                 WR4(mh, MACREG_REG_GEN_PTR, OpMode);
 2665                 DELAY(FW_CHECK_USECS);
 2666                 if (RD4(mh, MACREG_REG_INT_CODE) == FwReadySignature) {
 2667                         WR4(mh, MACREG_REG_INT_CODE, 0x00);
 2668                         return mwlResetHalState(mh);
 2669                 }
 2670         }
 2671         return ETIMEDOUT;
 2672 bad:
 2673         mwlFwReset(mh);
 2674 bad2:
 2675         /* done with firmware... */
 2676         if (fwboot != NULL)
 2677                 firmware_put(fwboot, FIRMWARE_UNLOAD);
 2678         firmware_put(fw, FIRMWARE_UNLOAD);
 2679         return error;
 2680 }
 2681 
 2682 #ifdef MWLHAL_DEBUG
 2683 static const char *
 2684 mwlcmdname(int cmd)
 2685 {
 2686         static char buf[12];
 2687 #define CMD(x)  case HostCmd_CMD_##x: return #x
 2688         switch (cmd) {
 2689         CMD(CODE_DNLD);
 2690         CMD(GET_HW_SPEC);
 2691         CMD(SET_HW_SPEC);
 2692         CMD(MAC_MULTICAST_ADR);
 2693         CMD(802_11_GET_STAT);
 2694         CMD(MAC_REG_ACCESS);
 2695         CMD(BBP_REG_ACCESS);
 2696         CMD(RF_REG_ACCESS);
 2697         CMD(802_11_RADIO_CONTROL);
 2698         CMD(802_11_RF_TX_POWER);
 2699         CMD(802_11_RF_ANTENNA);
 2700         CMD(SET_BEACON);
 2701         CMD(SET_RF_CHANNEL);
 2702         CMD(SET_AID);
 2703         CMD(SET_INFRA_MODE);
 2704         CMD(SET_G_PROTECT_FLAG);
 2705         CMD(802_11_RTS_THSD);
 2706         CMD(802_11_SET_SLOT);
 2707         CMD(SET_EDCA_PARAMS);
 2708         CMD(802_11H_DETECT_RADAR);
 2709         CMD(SET_WMM_MODE);
 2710         CMD(HT_GUARD_INTERVAL);
 2711         CMD(SET_FIXED_RATE);
 2712         CMD(SET_LINKADAPT_CS_MODE);
 2713         CMD(SET_MAC_ADDR);
 2714         CMD(SET_RATE_ADAPT_MODE);
 2715         CMD(BSS_START);
 2716         CMD(SET_NEW_STN);
 2717         CMD(SET_KEEP_ALIVE);
 2718         CMD(SET_APMODE);
 2719         CMD(SET_SWITCH_CHANNEL);
 2720         CMD(UPDATE_ENCRYPTION);
 2721         CMD(BASTREAM);
 2722         CMD(SET_RIFS);
 2723         CMD(SET_N_PROTECT_FLAG);
 2724         CMD(SET_N_PROTECT_OPMODE);
 2725         CMD(SET_OPTIMIZATION_LEVEL);
 2726         CMD(GET_CALTABLE);
 2727         CMD(SET_MIMOPSHT);
 2728         CMD(GET_BEACON);
 2729         CMD(SET_REGION_CODE);
 2730         CMD(SET_POWERSAVESTATION);
 2731         CMD(SET_TIM);
 2732         CMD(GET_TIM);
 2733         CMD(GET_SEQNO);
 2734         CMD(DWDS_ENABLE);
 2735         CMD(AMPDU_RETRY_RATEDROP_MODE);
 2736         CMD(CFEND_ENABLE);
 2737         }
 2738         snprintf(buf, sizeof(buf), "0x%x", cmd);
 2739         return buf;
 2740 #undef CMD
 2741 }
 2742 
 2743 static void
 2744 dumpresult(struct mwl_hal_priv *mh, int showresult)
 2745 {
 2746         const FWCmdHdr *h = (const FWCmdHdr *)mh->mh_cmdbuf;
 2747         const uint8_t *cp;
 2748         int len, i;
 2749 
 2750         len = le16toh(h->Length);
 2751 #ifdef MWL_MBSS_SUPPORT
 2752         device_printf(mh->mh_dev, "Cmd %s Length %d SeqNum %d MacId %d",
 2753             mwlcmdname(le16toh(h->Cmd) &~ 0x8000), len, h->SeqNum, h->MacId);
 2754 #else
 2755         device_printf(mh->mh_dev, "Cmd %s Length %d SeqNum %d",
 2756             mwlcmdname(le16toh(h->Cmd) &~ 0x8000), len, le16toh(h->SeqNum));
 2757 #endif
 2758         if (showresult) {
 2759                 const char *results[] =
 2760                     { "OK", "ERROR", "NOT_SUPPORT", "PENDING", "BUSY",
 2761                       "PARTIAL_DATA" };
 2762                 int result = le16toh(h->Result);
 2763 
 2764                 if (result <= HostCmd_RESULT_PARTIAL_DATA)
 2765                         printf(" Result %s", results[result]);
 2766                 else
 2767                         printf(" Result %d", result);
 2768         }
 2769         cp = (const uint8_t *)h;
 2770         for (i = 0; i < len; i++) {
 2771                 if ((i % 16) == 0)
 2772                         printf("\n%02x", cp[i]);
 2773                 else
 2774                         printf(" %02x", cp[i]);
 2775         }
 2776         printf("\n");
 2777 }
 2778 #endif /* MWLHAL_DEBUG */

Cache object: 49e872a35f2a559e3928f9a4e629a99b


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.