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