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