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