xref: /freebsd/sys/dev/ath/if_ath_alq.c (revision 4d846d260e2b9a3d4d0a701462568268cbfe7a5b)
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