xref: /dflybsd-src/sys/dev/netif/iwm/if_iwm_notif_wait.c (revision 6acbba79fd1a245dc4f49a6e542db4c015d39b8e)
194dc1dadSImre Vadász /*-
294dc1dadSImre Vadász  * Based on BSD-licensed source modules in the Linux iwlwifi driver,
394dc1dadSImre Vadász  * which were used as the reference documentation for this implementation.
494dc1dadSImre Vadász  *
594dc1dadSImre Vadász  ******************************************************************************
694dc1dadSImre Vadász  *
794dc1dadSImre Vadász  * This file is provided under a dual BSD/GPLv2 license.  When using or
894dc1dadSImre Vadász  * redistributing this file, you may do so under either license.
994dc1dadSImre Vadász  *
1094dc1dadSImre Vadász  * GPL LICENSE SUMMARY
1194dc1dadSImre Vadász  *
1294dc1dadSImre Vadász  * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
1394dc1dadSImre Vadász  * Copyright(c) 2015 Intel Deutschland GmbH
1494dc1dadSImre Vadász  *
1594dc1dadSImre Vadász  * This program is free software; you can redistribute it and/or modify
1694dc1dadSImre Vadász  * it under the terms of version 2 of the GNU General Public License as
1794dc1dadSImre Vadász  * published by the Free Software Foundation.
1894dc1dadSImre Vadász  *
1994dc1dadSImre Vadász  * This program is distributed in the hope that it will be useful, but
2094dc1dadSImre Vadász  * WITHOUT ANY WARRANTY; without even the implied warranty of
2194dc1dadSImre Vadász  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
2294dc1dadSImre Vadász  * General Public License for more details.
2394dc1dadSImre Vadász  *
2494dc1dadSImre Vadász  * You should have received a copy of the GNU General Public License
2594dc1dadSImre Vadász  * along with this program; if not, write to the Free Software
2694dc1dadSImre Vadász  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
2794dc1dadSImre Vadász  * USA
2894dc1dadSImre Vadász  *
2994dc1dadSImre Vadász  * The full GNU General Public License is included in this distribution
3094dc1dadSImre Vadász  * in the file called COPYING.
3194dc1dadSImre Vadász  *
3294dc1dadSImre Vadász  * Contact Information:
3394dc1dadSImre Vadász  *  Intel Linux Wireless <linuxwifi@intel.com>
3494dc1dadSImre Vadász  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
3594dc1dadSImre Vadász  *
3694dc1dadSImre Vadász  * BSD LICENSE
3794dc1dadSImre Vadász  *
3894dc1dadSImre Vadász  * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
3994dc1dadSImre Vadász  * All rights reserved.
4094dc1dadSImre Vadász  *
4194dc1dadSImre Vadász  * Redistribution and use in source and binary forms, with or without
4294dc1dadSImre Vadász  * modification, are permitted provided that the following conditions
4394dc1dadSImre Vadász  * are met:
4494dc1dadSImre Vadász  *
4594dc1dadSImre Vadász  *  * Redistributions of source code must retain the above copyright
4694dc1dadSImre Vadász  *    notice, this list of conditions and the following disclaimer.
4794dc1dadSImre Vadász  *  * Redistributions in binary form must reproduce the above copyright
4894dc1dadSImre Vadász  *    notice, this list of conditions and the following disclaimer in
4994dc1dadSImre Vadász  *    the documentation and/or other materials provided with the
5094dc1dadSImre Vadász  *    distribution.
5194dc1dadSImre Vadász  *  * Neither the name Intel Corporation nor the names of its
5294dc1dadSImre Vadász  *    contributors may be used to endorse or promote products derived
5394dc1dadSImre Vadász  *    from this software without specific prior written permission.
5494dc1dadSImre Vadász  *
5594dc1dadSImre Vadász  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
5694dc1dadSImre Vadász  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5794dc1dadSImre Vadász  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
5894dc1dadSImre Vadász  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
5994dc1dadSImre Vadász  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
6094dc1dadSImre Vadász  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
6194dc1dadSImre Vadász  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
6294dc1dadSImre Vadász  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
6394dc1dadSImre Vadász  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
6494dc1dadSImre Vadász  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
6594dc1dadSImre Vadász  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
6694dc1dadSImre Vadász  *
6794dc1dadSImre Vadász  *****************************************************************************/
68*6acbba79SMatthew Dillon 
6994dc1dadSImre Vadász #include <sys/param.h>
7094dc1dadSImre Vadász #include <sys/systm.h>
7194dc1dadSImre Vadász #include <sys/bus.h>
7294dc1dadSImre Vadász #include <sys/kernel.h>
7394dc1dadSImre Vadász #include <sys/lock.h>
74*6acbba79SMatthew Dillon #include <sys/malloc.h>
7594dc1dadSImre Vadász #include <sys/queue.h>
7694dc1dadSImre Vadász 
7794dc1dadSImre Vadász #include "if_iwm_notif_wait.h"
7894dc1dadSImre Vadász 
79*6acbba79SMatthew Dillon #define	IWM_WAIT_LOCK_INIT(_n, _s) \
80*6acbba79SMatthew Dillon 	lockinit(&(_n)->lk_lk, (_s), 0, 0)
81*6acbba79SMatthew Dillon #define	IWM_WAIT_LOCK(_n)		lockmgr(&(_n)->lk_lk, LK_EXCLUSIVE)
82*6acbba79SMatthew Dillon #define	IWM_WAIT_UNLOCK(_n)		lockmgr(&(_n)->lk_lk, LK_RELEASE)
83*6acbba79SMatthew Dillon #define	IWM_WAIT_LOCK_DESTROY(_n)	lockuninit(&(_n)->lk_lk)
84*6acbba79SMatthew Dillon 
8594dc1dadSImre Vadász struct iwm_notif_wait_data {
86*6acbba79SMatthew Dillon 	struct lock lk_lk;
87*6acbba79SMatthew Dillon 	char lk_buf[32];
8894dc1dadSImre Vadász 	STAILQ_HEAD(, iwm_notification_wait) list;
8994dc1dadSImre Vadász 	struct iwm_softc *sc;
9094dc1dadSImre Vadász };
9194dc1dadSImre Vadász 
9294dc1dadSImre Vadász struct iwm_notif_wait_data *
iwm_notification_wait_init(struct iwm_softc * sc)9394dc1dadSImre Vadász iwm_notification_wait_init(struct iwm_softc *sc)
9494dc1dadSImre Vadász {
9594dc1dadSImre Vadász 	struct iwm_notif_wait_data *data;
9694dc1dadSImre Vadász 
97*6acbba79SMatthew Dillon 	data = kmalloc(sizeof(*data), M_DEVBUF, M_INTWAIT | M_ZERO);
9894dc1dadSImre Vadász 	if (data != NULL) {
99*6acbba79SMatthew Dillon 		ksnprintf(data->lk_buf, 32, "iwm wait_notif");
100*6acbba79SMatthew Dillon 		IWM_WAIT_LOCK_INIT(data, data->lk_buf);
10194dc1dadSImre Vadász 		STAILQ_INIT(&data->list);
10294dc1dadSImre Vadász 		data->sc = sc;
10394dc1dadSImre Vadász 	}
10494dc1dadSImre Vadász 
10594dc1dadSImre Vadász 	return data;
10694dc1dadSImre Vadász }
10794dc1dadSImre Vadász 
10894dc1dadSImre Vadász void
iwm_notification_wait_free(struct iwm_notif_wait_data * notif_data)10994dc1dadSImre Vadász iwm_notification_wait_free(struct iwm_notif_wait_data *notif_data)
11094dc1dadSImre Vadász {
111*6acbba79SMatthew Dillon 	KASSERT(STAILQ_EMPTY(&notif_data->list), ("notif list isn't empty"));
112*6acbba79SMatthew Dillon 	IWM_WAIT_LOCK_DESTROY(notif_data);
11394dc1dadSImre Vadász 	kfree(notif_data, M_DEVBUF);
11494dc1dadSImre Vadász }
11594dc1dadSImre Vadász 
11694dc1dadSImre Vadász /* XXX Get rid of separate cmd argument, like in iwlwifi's code */
11794dc1dadSImre Vadász void
iwm_notification_wait_notify(struct iwm_notif_wait_data * notif_data,uint16_t cmd,struct iwm_rx_packet * pkt)11894dc1dadSImre Vadász iwm_notification_wait_notify(struct iwm_notif_wait_data *notif_data,
11994dc1dadSImre Vadász     uint16_t cmd, struct iwm_rx_packet *pkt)
12094dc1dadSImre Vadász {
12194dc1dadSImre Vadász 	struct iwm_notification_wait *wait_entry;
12294dc1dadSImre Vadász 
123*6acbba79SMatthew Dillon 	IWM_WAIT_LOCK(notif_data);
12494dc1dadSImre Vadász 	STAILQ_FOREACH(wait_entry, &notif_data->list, entry) {
12594dc1dadSImre Vadász 		int found = FALSE;
12694dc1dadSImre Vadász 		int i;
12794dc1dadSImre Vadász 
12894dc1dadSImre Vadász 		/*
12994dc1dadSImre Vadász 		 * If it already finished (triggered) or has been
13094dc1dadSImre Vadász 		 * aborted then don't evaluate it again to avoid races,
13194dc1dadSImre Vadász 		 * Otherwise the function could be called again even
13294dc1dadSImre Vadász 		 * though it returned true before
13394dc1dadSImre Vadász 		 */
13494dc1dadSImre Vadász 		if (wait_entry->triggered || wait_entry->aborted)
13594dc1dadSImre Vadász 			continue;
13694dc1dadSImre Vadász 
13794dc1dadSImre Vadász 		for (i = 0; i < wait_entry->n_cmds; i++) {
13894dc1dadSImre Vadász 			if (cmd == wait_entry->cmds[i]) {
13994dc1dadSImre Vadász 				found = TRUE;
14094dc1dadSImre Vadász 				break;
14194dc1dadSImre Vadász 			}
14294dc1dadSImre Vadász 		}
14394dc1dadSImre Vadász 		if (!found)
14494dc1dadSImre Vadász 			continue;
14594dc1dadSImre Vadász 
14694dc1dadSImre Vadász 		if (!wait_entry->fn ||
14794dc1dadSImre Vadász 		    wait_entry->fn(notif_data->sc, pkt, wait_entry->fn_data)) {
14894dc1dadSImre Vadász 			wait_entry->triggered = 1;
14994dc1dadSImre Vadász 			wakeup(wait_entry);
15094dc1dadSImre Vadász 		}
15194dc1dadSImre Vadász 	}
152*6acbba79SMatthew Dillon 	IWM_WAIT_UNLOCK(notif_data);
15394dc1dadSImre Vadász }
15494dc1dadSImre Vadász 
15594dc1dadSImre Vadász void
iwm_abort_notification_waits(struct iwm_notif_wait_data * notif_data)15694dc1dadSImre Vadász iwm_abort_notification_waits(struct iwm_notif_wait_data *notif_data)
15794dc1dadSImre Vadász {
15894dc1dadSImre Vadász 	struct iwm_notification_wait *wait_entry;
15994dc1dadSImre Vadász 
160*6acbba79SMatthew Dillon 	IWM_WAIT_LOCK(notif_data);
16194dc1dadSImre Vadász 	STAILQ_FOREACH(wait_entry, &notif_data->list, entry) {
16294dc1dadSImre Vadász 		wait_entry->aborted = 1;
16394dc1dadSImre Vadász 		wakeup(wait_entry);
16494dc1dadSImre Vadász 	}
165*6acbba79SMatthew Dillon 	IWM_WAIT_UNLOCK(notif_data);
16694dc1dadSImre Vadász }
16794dc1dadSImre Vadász 
16894dc1dadSImre Vadász void
iwm_init_notification_wait(struct iwm_notif_wait_data * notif_data,struct iwm_notification_wait * wait_entry,const uint16_t * cmds,int n_cmds,int (* fn)(struct iwm_softc * sc,struct iwm_rx_packet * pkt,void * data),void * fn_data)16994dc1dadSImre Vadász iwm_init_notification_wait(struct iwm_notif_wait_data *notif_data,
17094dc1dadSImre Vadász     struct iwm_notification_wait *wait_entry, const uint16_t *cmds, int n_cmds,
17194dc1dadSImre Vadász     int (*fn)(struct iwm_softc *sc, struct iwm_rx_packet *pkt, void *data),
17294dc1dadSImre Vadász     void *fn_data)
17394dc1dadSImre Vadász {
174*6acbba79SMatthew Dillon 	KASSERT(n_cmds <= IWM_MAX_NOTIF_CMDS,
175*6acbba79SMatthew Dillon 	    ("n_cmds %d is too large", n_cmds));
17694dc1dadSImre Vadász 	wait_entry->fn = fn;
17794dc1dadSImre Vadász 	wait_entry->fn_data = fn_data;
17894dc1dadSImre Vadász 	wait_entry->n_cmds = n_cmds;
17994dc1dadSImre Vadász 	memcpy(wait_entry->cmds, cmds, n_cmds * sizeof(uint16_t));
18094dc1dadSImre Vadász 	wait_entry->triggered = 0;
18194dc1dadSImre Vadász 	wait_entry->aborted = 0;
18294dc1dadSImre Vadász 
183*6acbba79SMatthew Dillon 	IWM_WAIT_LOCK(notif_data);
18494dc1dadSImre Vadász 	STAILQ_INSERT_TAIL(&notif_data->list, wait_entry, entry);
185*6acbba79SMatthew Dillon 	IWM_WAIT_UNLOCK(notif_data);
18694dc1dadSImre Vadász }
18794dc1dadSImre Vadász 
18894dc1dadSImre Vadász int
iwm_wait_notification(struct iwm_notif_wait_data * notif_data,struct iwm_notification_wait * wait_entry,int timeout)18994dc1dadSImre Vadász iwm_wait_notification(struct iwm_notif_wait_data *notif_data,
19094dc1dadSImre Vadász     struct iwm_notification_wait *wait_entry, int timeout)
19194dc1dadSImre Vadász {
19294dc1dadSImre Vadász 	int ret = 0;
19394dc1dadSImre Vadász 
194*6acbba79SMatthew Dillon 	IWM_WAIT_LOCK(notif_data);
19594dc1dadSImre Vadász 	if (!wait_entry->triggered && !wait_entry->aborted) {
196*6acbba79SMatthew Dillon 		ret = lksleep(wait_entry, &notif_data->lk_lk, 0, "iwm_notif",
19794dc1dadSImre Vadász 		    timeout);
19894dc1dadSImre Vadász 	}
19994dc1dadSImre Vadász 	STAILQ_REMOVE(&notif_data->list, wait_entry, iwm_notification_wait,
20094dc1dadSImre Vadász 	    entry);
201*6acbba79SMatthew Dillon 	IWM_WAIT_UNLOCK(notif_data);
20294dc1dadSImre Vadász 
20394dc1dadSImre Vadász 	return ret;
20494dc1dadSImre Vadász }
20594dc1dadSImre Vadász 
20694dc1dadSImre Vadász void
iwm_remove_notification(struct iwm_notif_wait_data * notif_data,struct iwm_notification_wait * wait_entry)20794dc1dadSImre Vadász iwm_remove_notification(struct iwm_notif_wait_data *notif_data,
20894dc1dadSImre Vadász     struct iwm_notification_wait *wait_entry)
20994dc1dadSImre Vadász {
210*6acbba79SMatthew Dillon 	IWM_WAIT_LOCK(notif_data);
21194dc1dadSImre Vadász 	STAILQ_REMOVE(&notif_data->list, wait_entry, iwm_notification_wait,
21294dc1dadSImre Vadász 	    entry);
213*6acbba79SMatthew Dillon 	IWM_WAIT_UNLOCK(notif_data);
21494dc1dadSImre Vadász }
215