12a2441c9SAdrian Chadd /*- 22a2441c9SAdrian Chadd * Copyright (c) 2012 Adrian Chadd 32a2441c9SAdrian Chadd * All rights reserved. 42a2441c9SAdrian Chadd * 52a2441c9SAdrian Chadd * Redistribution and use in source and binary forms, with or without 62a2441c9SAdrian Chadd * modification, are permitted provided that the following conditions 72a2441c9SAdrian Chadd * are met: 82a2441c9SAdrian Chadd * 1. Redistributions of source code must retain the above copyright 92a2441c9SAdrian Chadd * notice, this list of conditions and the following disclaimer, 102a2441c9SAdrian Chadd * without modification. 112a2441c9SAdrian Chadd * 2. Redistributions in binary form must reproduce at minimum a disclaimer 122a2441c9SAdrian Chadd * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 132a2441c9SAdrian Chadd * redistribution must be conditioned upon including a substantially 142a2441c9SAdrian Chadd * similar Disclaimer requirement for further binary redistribution. 152a2441c9SAdrian Chadd * 162a2441c9SAdrian Chadd * NO WARRANTY 172a2441c9SAdrian Chadd * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 182a2441c9SAdrian Chadd * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 192a2441c9SAdrian Chadd * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 202a2441c9SAdrian Chadd * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 212a2441c9SAdrian Chadd * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 222a2441c9SAdrian Chadd * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 232a2441c9SAdrian Chadd * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 242a2441c9SAdrian Chadd * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 252a2441c9SAdrian Chadd * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 262a2441c9SAdrian Chadd * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 272a2441c9SAdrian Chadd * THE POSSIBILITY OF SUCH DAMAGES. 282a2441c9SAdrian Chadd * 292a2441c9SAdrian Chadd * $FreeBSD$ 302a2441c9SAdrian Chadd */ 312a2441c9SAdrian Chadd #include "opt_ah.h" 322a2441c9SAdrian Chadd #include "opt_ath.h" 332a2441c9SAdrian Chadd 342a2441c9SAdrian Chadd #include <sys/param.h> 352a2441c9SAdrian Chadd #include <sys/systm.h> 362a2441c9SAdrian Chadd #include <sys/kernel.h> 372a2441c9SAdrian Chadd #include <sys/module.h> 382a2441c9SAdrian Chadd #include <sys/sysctl.h> 392a2441c9SAdrian Chadd #include <sys/bus.h> 402a2441c9SAdrian Chadd #include <sys/malloc.h> 412a2441c9SAdrian Chadd #include <sys/proc.h> 422a2441c9SAdrian Chadd #include <sys/pcpu.h> 432a2441c9SAdrian Chadd #include <sys/lock.h> 442a2441c9SAdrian Chadd #include <sys/mutex.h> 452a2441c9SAdrian Chadd #include <sys/alq.h> 46956d4fb9SAdrian Chadd #include <sys/endian.h> 47*81561d04SAdrian Chadd #include <sys/time.h> 482a2441c9SAdrian Chadd 492a2441c9SAdrian Chadd #include <dev/ath/if_ath_alq.h> 502a2441c9SAdrian Chadd 512a2441c9SAdrian Chadd #ifdef ATH_DEBUG_ALQ 522a2441c9SAdrian Chadd static struct ale * 532a2441c9SAdrian Chadd if_ath_alq_get(struct if_ath_alq *alq, int len) 542a2441c9SAdrian Chadd { 552a2441c9SAdrian Chadd struct ale *ale; 562a2441c9SAdrian Chadd 572a2441c9SAdrian Chadd if (alq->sc_alq_isactive == 0) 582a2441c9SAdrian Chadd return (NULL); 592a2441c9SAdrian Chadd 602a2441c9SAdrian Chadd ale = alq_getn(alq->sc_alq_alq, len, ALQ_NOWAIT); 612a2441c9SAdrian Chadd if (! ale) 622a2441c9SAdrian Chadd alq->sc_alq_numlost++; 632a2441c9SAdrian Chadd return (ale); 642a2441c9SAdrian Chadd } 652a2441c9SAdrian Chadd 662a2441c9SAdrian Chadd void 672a2441c9SAdrian Chadd if_ath_alq_init(struct if_ath_alq *alq, const char *devname) 682a2441c9SAdrian Chadd { 692a2441c9SAdrian Chadd 702a2441c9SAdrian Chadd bzero(alq, sizeof(*alq)); 712a2441c9SAdrian Chadd 722a2441c9SAdrian Chadd strncpy(alq->sc_alq_devname, devname, ATH_ALQ_DEVNAME_LEN); 73a64438faSAdrian Chadd printf("%s (%s): attached\n", __func__, alq->sc_alq_devname); 742a2441c9SAdrian Chadd snprintf(alq->sc_alq_filename, ATH_ALQ_FILENAME_LEN, 752a2441c9SAdrian Chadd "/tmp/ath_%s_alq.log", alq->sc_alq_devname); 762a2441c9SAdrian Chadd 772a2441c9SAdrian Chadd /* XXX too conservative, right? */ 782a2441c9SAdrian Chadd alq->sc_alq_qsize = (64*1024); 792a2441c9SAdrian Chadd } 802a2441c9SAdrian Chadd 812a2441c9SAdrian Chadd void 82956d4fb9SAdrian Chadd if_ath_alq_setcfg(struct if_ath_alq *alq, uint32_t macVer, 83956d4fb9SAdrian Chadd uint32_t macRev, uint32_t phyRev, uint32_t halMagic) 84956d4fb9SAdrian Chadd { 85956d4fb9SAdrian Chadd 86956d4fb9SAdrian Chadd /* Store these in network order */ 87956d4fb9SAdrian Chadd alq->sc_alq_cfg.sc_mac_version = htobe32(macVer); 88956d4fb9SAdrian Chadd alq->sc_alq_cfg.sc_mac_revision = htobe32(macRev); 89956d4fb9SAdrian Chadd alq->sc_alq_cfg.sc_phy_rev = htobe32(phyRev); 90956d4fb9SAdrian Chadd alq->sc_alq_cfg.sc_hal_magic = htobe32(halMagic); 91956d4fb9SAdrian Chadd } 92956d4fb9SAdrian Chadd 93956d4fb9SAdrian Chadd void 942a2441c9SAdrian Chadd if_ath_alq_tidyup(struct if_ath_alq *alq) 952a2441c9SAdrian Chadd { 962a2441c9SAdrian Chadd 972a2441c9SAdrian Chadd if_ath_alq_stop(alq); 982a2441c9SAdrian Chadd printf("%s (%s): detached\n", __func__, alq->sc_alq_devname); 992a2441c9SAdrian Chadd bzero(alq, sizeof(*alq)); 1002a2441c9SAdrian Chadd } 1012a2441c9SAdrian Chadd 1022a2441c9SAdrian Chadd int 1032a2441c9SAdrian Chadd if_ath_alq_start(struct if_ath_alq *alq) 1042a2441c9SAdrian Chadd { 1052a2441c9SAdrian Chadd int error; 1062a2441c9SAdrian Chadd 1072a2441c9SAdrian Chadd if (alq->sc_alq_isactive) 1082a2441c9SAdrian Chadd return (0); 1092a2441c9SAdrian Chadd 1102a2441c9SAdrian Chadd /* 1112a2441c9SAdrian Chadd * Create a variable-length ALQ. 1122a2441c9SAdrian Chadd */ 1132a2441c9SAdrian Chadd error = alq_open(&alq->sc_alq_alq, alq->sc_alq_filename, 1142a2441c9SAdrian Chadd curthread->td_ucred, ALQ_DEFAULT_CMODE, 1152a2441c9SAdrian Chadd alq->sc_alq_qsize, 0); 1162a2441c9SAdrian Chadd 1172a2441c9SAdrian Chadd if (error != 0) { 1182a2441c9SAdrian Chadd printf("%s (%s): failed, err=%d\n", __func__, 1192a2441c9SAdrian Chadd alq->sc_alq_devname, error); 1202a2441c9SAdrian Chadd } else { 1212a2441c9SAdrian Chadd printf("%s (%s): opened\n", __func__, alq->sc_alq_devname); 1222a2441c9SAdrian Chadd alq->sc_alq_isactive = 1; 123956d4fb9SAdrian Chadd if_ath_alq_post(alq, ATH_ALQ_INIT_STATE, 124956d4fb9SAdrian Chadd sizeof (struct if_ath_alq_init_state), 125956d4fb9SAdrian Chadd (char *) &alq->sc_alq_cfg); 1262a2441c9SAdrian Chadd } 1272a2441c9SAdrian Chadd return (error); 1282a2441c9SAdrian Chadd } 1292a2441c9SAdrian Chadd 1302a2441c9SAdrian Chadd int 1312a2441c9SAdrian Chadd if_ath_alq_stop(struct if_ath_alq *alq) 1322a2441c9SAdrian Chadd { 1332a2441c9SAdrian Chadd 1342a2441c9SAdrian Chadd if (alq->sc_alq_isactive == 0) 1352a2441c9SAdrian Chadd return (0); 1362a2441c9SAdrian Chadd 1372a2441c9SAdrian Chadd printf("%s (%s): closed\n", __func__, alq->sc_alq_devname); 1382a2441c9SAdrian Chadd 1392a2441c9SAdrian Chadd alq->sc_alq_isactive = 0; 1402a2441c9SAdrian Chadd alq_close(alq->sc_alq_alq); 1412a2441c9SAdrian Chadd alq->sc_alq_alq = NULL; 1422a2441c9SAdrian Chadd 1432a2441c9SAdrian Chadd return (0); 1442a2441c9SAdrian Chadd } 1452a2441c9SAdrian Chadd 1462a2441c9SAdrian Chadd /* 1472a2441c9SAdrian Chadd * Post a debug message to the ALQ. 1482a2441c9SAdrian Chadd * 1492a2441c9SAdrian Chadd * "len" is the size of the buf payload in bytes. 1502a2441c9SAdrian Chadd */ 1512a2441c9SAdrian Chadd void 1522a2441c9SAdrian Chadd if_ath_alq_post(struct if_ath_alq *alq, uint16_t op, uint16_t len, 1532a2441c9SAdrian Chadd const char *buf) 1542a2441c9SAdrian Chadd { 1552a2441c9SAdrian Chadd struct if_ath_alq_hdr *ap; 1562a2441c9SAdrian Chadd struct ale *ale; 157*81561d04SAdrian Chadd struct timeval tv; 1582a2441c9SAdrian Chadd 1592a2441c9SAdrian Chadd if (! if_ath_alq_checkdebug(alq, op)) 1602a2441c9SAdrian Chadd return; 1612a2441c9SAdrian Chadd 162*81561d04SAdrian Chadd microtime(&tv); 163*81561d04SAdrian Chadd 1642a2441c9SAdrian Chadd /* 1652a2441c9SAdrian Chadd * Enforce some semblence of sanity on 'len'. 1662a2441c9SAdrian Chadd * Although strictly speaking, any length is possible - 1672a2441c9SAdrian Chadd * just be conservative so things don't get out of hand. 1682a2441c9SAdrian Chadd */ 1692a2441c9SAdrian Chadd if (len > ATH_ALQ_PAYLOAD_LEN) 1702a2441c9SAdrian Chadd len = ATH_ALQ_PAYLOAD_LEN; 1712a2441c9SAdrian Chadd 1722a2441c9SAdrian Chadd ale = if_ath_alq_get(alq, len + sizeof(struct if_ath_alq_hdr)); 1732a2441c9SAdrian Chadd 1742a2441c9SAdrian Chadd if (ale == NULL) 1752a2441c9SAdrian Chadd return; 1762a2441c9SAdrian Chadd 1772a2441c9SAdrian Chadd ap = (struct if_ath_alq_hdr *) ale->ae_data; 178956d4fb9SAdrian Chadd ap->threadid = htobe64((uint64_t) curthread->td_tid); 179*81561d04SAdrian Chadd ap->tstamp_sec = htobe32((uint32_t) tv.tv_sec); 180*81561d04SAdrian Chadd ap->tstamp_usec = htobe32((uint32_t) tv.tv_usec); 181956d4fb9SAdrian Chadd ap->op = htobe16(op); 182956d4fb9SAdrian Chadd ap->len = htobe16(len); 1832a2441c9SAdrian Chadd 1842a2441c9SAdrian Chadd /* 1852a2441c9SAdrian Chadd * Copy the payload _after_ the header field. 1862a2441c9SAdrian Chadd */ 1872a2441c9SAdrian Chadd memcpy(((char *) ap) + sizeof(struct if_ath_alq_hdr), 1882a2441c9SAdrian Chadd buf, 189956d4fb9SAdrian Chadd len); 1902a2441c9SAdrian Chadd 1912a2441c9SAdrian Chadd alq_post(alq->sc_alq_alq, ale); 1922a2441c9SAdrian Chadd } 1932a2441c9SAdrian Chadd #endif /* ATH_DEBUG */ 194