ntb_transport.c revision 289346
1250079Scarl/*-
2250079Scarl * Copyright (C) 2013 Intel Corporation
3250079Scarl * All rights reserved.
4250079Scarl *
5250079Scarl * Redistribution and use in source and binary forms, with or without
6250079Scarl * modification, are permitted provided that the following conditions
7250079Scarl * are met:
8250079Scarl * 1. Redistributions of source code must retain the above copyright
9250079Scarl *    notice, this list of conditions and the following disclaimer.
10250079Scarl * 2. Redistributions in binary form must reproduce the above copyright
11250079Scarl *    notice, this list of conditions and the following disclaimer in the
12250079Scarl *    documentation and/or other materials provided with the distribution.
13250079Scarl *
14250079Scarl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15250079Scarl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16250079Scarl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17250079Scarl * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18250079Scarl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19250079Scarl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20250079Scarl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21250079Scarl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22250079Scarl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23250079Scarl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24250079Scarl * SUCH DAMAGE.
25250079Scarl */
26250079Scarl
27250079Scarl#include <sys/cdefs.h>
28250079Scarl__FBSDID("$FreeBSD: head/sys/dev/ntb/if_ntb/if_ntb.c 289346 2015-10-14 23:47:52Z cem $");
29250079Scarl
30250079Scarl#include <sys/param.h>
31250079Scarl#include <sys/kernel.h>
32250079Scarl#include <sys/systm.h>
33250079Scarl#include <sys/bus.h>
34250079Scarl#include <sys/ktr.h>
35289281Scem#include <sys/limits.h>
36250079Scarl#include <sys/lock.h>
37250079Scarl#include <sys/malloc.h>
38250079Scarl#include <sys/module.h>
39250079Scarl#include <sys/mutex.h>
40250079Scarl#include <sys/queue.h>
41250079Scarl#include <sys/socket.h>
42250079Scarl#include <sys/sockio.h>
43289207Scem#include <sys/sysctl.h>
44250079Scarl#include <sys/taskqueue.h>
45250079Scarl#include <net/if.h>
46250079Scarl#include <net/if_media.h>
47250079Scarl#include <net/if_types.h>
48250079Scarl#include <net/if_var.h>
49250079Scarl#include <net/bpf.h>
50250079Scarl#include <net/ethernet.h>
51250079Scarl#include <vm/vm.h>
52250079Scarl#include <vm/pmap.h>
53250079Scarl#include <machine/bus.h>
54250079Scarl#include <machine/cpufunc.h>
55250079Scarl#include <machine/pmap.h>
56250079Scarl
57250079Scarl#include "../ntb_hw/ntb_hw.h"
58250079Scarl
59250079Scarl/*
60250079Scarl * The Non-Transparent Bridge (NTB) is a device on some Intel processors that
61250079Scarl * allows you to connect two systems using a PCI-e link.
62250079Scarl *
63250079Scarl * This module contains a protocol for sending and receiving messages, and
64250079Scarl * exposes that protocol through a simulated ethernet device called ntb.
65250079Scarl *
66250079Scarl * NOTE: Much of the code in this module is shared with Linux. Any patches may
67250079Scarl * be picked up and redistributed in Linux with a dual GPL/BSD license.
68250079Scarl */
69250079Scarl
70250079Scarl/* TODO: These functions should really be part of the kernel */
71250079Scarl#define test_bit(pos, bitmap_addr)  (*(bitmap_addr) & 1UL << (pos))
72250079Scarl#define set_bit(pos, bitmap_addr)   *(bitmap_addr) |= 1UL << (pos)
73250079Scarl#define clear_bit(pos, bitmap_addr) *(bitmap_addr) &= ~(1UL << (pos))
74250079Scarl
75250079Scarl#define KTR_NTB KTR_SPARE3
76250079Scarl
77250079Scarl#define NTB_TRANSPORT_VERSION	3
78250079Scarl#define NTB_RX_MAX_PKTS		64
79250079Scarl#define	NTB_RXQ_SIZE		300
80250079Scarl
81250079Scarlstatic unsigned int transport_mtu = 0x4000 + ETHER_HDR_LEN + ETHER_CRC_LEN;
82289208Scem
83289208Scem/*
84289208Scem * This is an oversimplification to work around Xeon Errata.  The second client
85289208Scem * may be usable for unidirectional traffic.
86289208Scem */
87250079Scarlstatic unsigned int max_num_clients = 1;
88250079Scarl
89250079ScarlSTAILQ_HEAD(ntb_queue_list, ntb_queue_entry);
90250079Scarl
91250079Scarlstruct ntb_queue_entry {
92250079Scarl	/* ntb_queue list reference */
93250079Scarl	STAILQ_ENTRY(ntb_queue_entry) entry;
94250079Scarl
95250079Scarl	/* info on data to be transfered */
96250079Scarl	void		*cb_data;
97250079Scarl	void		*buf;
98250079Scarl	uint64_t	len;
99250079Scarl	uint64_t	flags;
100250079Scarl};
101250079Scarl
102250079Scarlstruct ntb_rx_info {
103250079Scarl	unsigned int entry;
104250079Scarl};
105250079Scarl
106250079Scarlstruct ntb_transport_qp {
107250079Scarl	struct ntb_netdev	*transport;
108250079Scarl	struct ntb_softc	*ntb;
109250079Scarl
110250079Scarl	void			*cb_data;
111250079Scarl
112250079Scarl	bool			client_ready;
113250079Scarl	bool			qp_link;
114255281Scarl	uint8_t			qp_num;	/* Only 64 QPs are allowed.  0-63 */
115250079Scarl
116250079Scarl	struct ntb_rx_info	*rx_info;
117250079Scarl	struct ntb_rx_info	*remote_rx_info;
118250079Scarl
119289341Scem	void (*tx_handler)(struct ntb_transport_qp *qp, void *qp_data,
120250079Scarl	    void *data, int len);
121250079Scarl	struct ntb_queue_list	tx_free_q;
122250079Scarl	struct mtx		ntb_tx_free_q_lock;
123250079Scarl	void			*tx_mw;
124250079Scarl	uint64_t		tx_index;
125250079Scarl	uint64_t		tx_max_entry;
126250079Scarl	uint64_t		tx_max_frame;
127250079Scarl
128289341Scem	void (*rx_handler)(struct ntb_transport_qp *qp, void *qp_data,
129250079Scarl	    void *data, int len);
130250079Scarl	struct ntb_queue_list	rx_pend_q;
131250079Scarl	struct ntb_queue_list	rx_free_q;
132250079Scarl	struct mtx		ntb_rx_pend_q_lock;
133250079Scarl	struct mtx		ntb_rx_free_q_lock;
134250079Scarl	struct task		rx_completion_task;
135250079Scarl	void			*rx_buff;
136250079Scarl	uint64_t		rx_index;
137250079Scarl	uint64_t		rx_max_entry;
138250079Scarl	uint64_t		rx_max_frame;
139250079Scarl
140289341Scem	void (*event_handler)(void *data, enum ntb_link_event status);
141250079Scarl	struct callout		link_work;
142250079Scarl	struct callout		queue_full;
143250079Scarl	struct callout		rx_full;
144250079Scarl
145250079Scarl	uint64_t		last_rx_no_buf;
146250079Scarl
147250079Scarl	/* Stats */
148250079Scarl	uint64_t		rx_bytes;
149250079Scarl	uint64_t		rx_pkts;
150250079Scarl	uint64_t		rx_ring_empty;
151250079Scarl	uint64_t		rx_err_no_buf;
152250079Scarl	uint64_t		rx_err_oflow;
153250079Scarl	uint64_t		rx_err_ver;
154250079Scarl	uint64_t		tx_bytes;
155250079Scarl	uint64_t		tx_pkts;
156250079Scarl	uint64_t		tx_ring_full;
157250079Scarl};
158250079Scarl
159250079Scarlstruct ntb_queue_handlers {
160289341Scem	void (*rx_handler)(struct ntb_transport_qp *qp, void *qp_data,
161250079Scarl	    void *data, int len);
162289341Scem	void (*tx_handler)(struct ntb_transport_qp *qp, void *qp_data,
163250079Scarl	    void *data, int len);
164289341Scem	void (*event_handler)(void *data, enum ntb_link_event status);
165250079Scarl};
166250079Scarl
167250079Scarl
168250079Scarlstruct ntb_transport_mw {
169250079Scarl	size_t		size;
170250079Scarl	void		*virt_addr;
171250079Scarl	vm_paddr_t	dma_addr;
172250079Scarl};
173250079Scarl
174250079Scarlstruct ntb_netdev {
175250079Scarl	struct ntb_softc	*ntb;
176250079Scarl	struct ifnet		*ifp;
177250079Scarl	struct ntb_transport_mw	mw[NTB_NUM_MW];
178250079Scarl	struct ntb_transport_qp	*qps;
179250079Scarl	uint64_t		max_qps;
180250079Scarl	uint64_t		qp_bitmap;
181250079Scarl	bool			transport_link;
182250079Scarl	struct callout		link_work;
183250079Scarl	struct ntb_transport_qp *qp;
184250079Scarl	uint64_t		bufsize;
185250079Scarl	u_char			eaddr[ETHER_ADDR_LEN];
186250079Scarl	struct mtx		tx_lock;
187250079Scarl	struct mtx		rx_lock;
188250079Scarl};
189250079Scarl
190250079Scarlstatic struct ntb_netdev net_softc;
191250079Scarl
192250079Scarlenum {
193250079Scarl	IF_NTB_DESC_DONE_FLAG = 1 << 0,
194250079Scarl	IF_NTB_LINK_DOWN_FLAG = 1 << 1,
195250079Scarl};
196250079Scarl
197250079Scarlstruct ntb_payload_header {
198250079Scarl	uint64_t ver;
199250079Scarl	uint64_t len;
200250079Scarl	uint64_t flags;
201250079Scarl};
202250079Scarl
203250079Scarlenum {
204289153Scem	/*
205289153Scem	 * The order of this enum is part of the if_ntb remote protocol.  Do
206289153Scem	 * not reorder without bumping protocol version (and it's probably best
207289153Scem	 * to keep the protocol in lock-step with the Linux NTB driver.
208289153Scem	 */
209250079Scarl	IF_NTB_VERSION = 0,
210289153Scem	IF_NTB_QP_LINKS,
211250079Scarl	IF_NTB_NUM_QPS,
212289153Scem	IF_NTB_NUM_MWS,
213289153Scem	/*
214289153Scem	 * N.B.: transport_link_work assumes MW1 enums = MW0 + 2.
215289153Scem	 */
216289153Scem	IF_NTB_MW0_SZ_HIGH,
217289153Scem	IF_NTB_MW0_SZ_LOW,
218289153Scem	IF_NTB_MW1_SZ_HIGH,
219289153Scem	IF_NTB_MW1_SZ_LOW,
220250079Scarl	IF_NTB_MAX_SPAD,
221250079Scarl};
222250079Scarl
223250079Scarl#define QP_TO_MW(qp)		((qp) % NTB_NUM_MW)
224250079Scarl#define NTB_QP_DEF_NUM_ENTRIES	100
225250079Scarl#define NTB_LINK_DOWN_TIMEOUT	10
226250079Scarl
227250079Scarlstatic int ntb_handle_module_events(struct module *m, int what, void *arg);
228250079Scarlstatic int ntb_setup_interface(void);
229250079Scarlstatic int ntb_teardown_interface(void);
230250079Scarlstatic void ntb_net_init(void *arg);
231250079Scarlstatic int ntb_ioctl(struct ifnet *ifp, u_long command, caddr_t data);
232250079Scarlstatic void ntb_start(struct ifnet *ifp);
233250079Scarlstatic void ntb_net_tx_handler(struct ntb_transport_qp *qp, void *qp_data,
234250079Scarl    void *data, int len);
235250079Scarlstatic void ntb_net_rx_handler(struct ntb_transport_qp *qp, void *qp_data,
236250079Scarl    void *data, int len);
237289340Scemstatic void ntb_net_event_handler(void *data, enum ntb_link_event status);
238250079Scarlstatic int ntb_transport_init(struct ntb_softc *ntb);
239250079Scarlstatic void ntb_transport_free(void *transport);
240250079Scarlstatic void ntb_transport_init_queue(struct ntb_netdev *nt,
241250079Scarl    unsigned int qp_num);
242250079Scarlstatic void ntb_transport_free_queue(struct ntb_transport_qp *qp);
243250079Scarlstatic struct ntb_transport_qp * ntb_transport_create_queue(void *data,
244250079Scarl    struct ntb_softc *pdev, const struct ntb_queue_handlers *handlers);
245250079Scarlstatic void ntb_transport_link_up(struct ntb_transport_qp *qp);
246250079Scarlstatic int ntb_transport_tx_enqueue(struct ntb_transport_qp *qp, void *cb,
247250079Scarl    void *data, unsigned int len);
248250079Scarlstatic int ntb_process_tx(struct ntb_transport_qp *qp,
249250079Scarl    struct ntb_queue_entry *entry);
250250079Scarlstatic void ntb_tx_copy_task(struct ntb_transport_qp *qp,
251250079Scarl    struct ntb_queue_entry *entry, void *offset);
252250079Scarlstatic void ntb_qp_full(void *arg);
253289281Scemstatic int ntb_transport_rxc_db(void *arg, int dummy);
254250079Scarlstatic void ntb_rx_pendq_full(void *arg);
255250079Scarlstatic int ntb_process_rxc(struct ntb_transport_qp *qp);
256250079Scarlstatic void ntb_rx_copy_task(struct ntb_transport_qp *qp,
257250079Scarl    struct ntb_queue_entry *entry, void *offset);
258250079Scarlstatic void ntb_rx_completion_task(void *arg, int pending);
259250079Scarlstatic void ntb_transport_event_callback(void *data, enum ntb_hw_event event);
260250079Scarlstatic void ntb_transport_link_work(void *arg);
261250079Scarlstatic int ntb_set_mw(struct ntb_netdev *nt, int num_mw, unsigned int size);
262289153Scemstatic void ntb_free_mw(struct ntb_netdev *nt, int num_mw);
263250079Scarlstatic void ntb_transport_setup_qp_mw(struct ntb_netdev *nt,
264250079Scarl    unsigned int qp_num);
265250079Scarlstatic void ntb_qp_link_work(void *arg);
266250079Scarlstatic void ntb_transport_link_cleanup(struct ntb_netdev *nt);
267250079Scarlstatic void ntb_qp_link_down(struct ntb_transport_qp *qp);
268250079Scarlstatic void ntb_qp_link_cleanup(struct ntb_transport_qp *qp);
269250079Scarlstatic void ntb_transport_link_down(struct ntb_transport_qp *qp);
270250079Scarlstatic void ntb_send_link_down(struct ntb_transport_qp *qp);
271250079Scarlstatic void ntb_list_add(struct mtx *lock, struct ntb_queue_entry *entry,
272250079Scarl    struct ntb_queue_list *list);
273250079Scarlstatic struct ntb_queue_entry *ntb_list_rm(struct mtx *lock,
274250079Scarl    struct ntb_queue_list *list);
275250079Scarlstatic void create_random_local_eui48(u_char *eaddr);
276250079Scarlstatic unsigned int ntb_transport_max_size(struct ntb_transport_qp *qp);
277250079Scarl
278250079ScarlMALLOC_DEFINE(M_NTB_IF, "if_ntb", "ntb network driver");
279250079Scarl
280250079Scarl/* Module setup and teardown */
281250079Scarlstatic int
282250079Scarlntb_handle_module_events(struct module *m, int what, void *arg)
283250079Scarl{
284250079Scarl	int err = 0;
285250079Scarl
286250079Scarl	switch (what) {
287250079Scarl	case MOD_LOAD:
288250079Scarl		err = ntb_setup_interface();
289250079Scarl		break;
290250079Scarl	case MOD_UNLOAD:
291250079Scarl		err = ntb_teardown_interface();
292250079Scarl		break;
293250079Scarl	default:
294250079Scarl		err = EOPNOTSUPP;
295250079Scarl		break;
296250079Scarl	}
297250079Scarl	return (err);
298250079Scarl}
299250079Scarl
300255271Scarlstatic moduledata_t if_ntb_mod = {
301255271Scarl	"if_ntb",
302250079Scarl	ntb_handle_module_events,
303250079Scarl	NULL
304250079Scarl};
305250079Scarl
306255271ScarlDECLARE_MODULE(if_ntb, if_ntb_mod, SI_SUB_KLD, SI_ORDER_ANY);
307255271ScarlMODULE_DEPEND(if_ntb, ntb_hw, 1, 1, 1);
308250079Scarl
309250079Scarlstatic int
310289209Scemntb_setup_interface(void)
311250079Scarl{
312250079Scarl	struct ifnet *ifp;
313250079Scarl	struct ntb_queue_handlers handlers = { ntb_net_rx_handler,
314250079Scarl	    ntb_net_tx_handler, ntb_net_event_handler };
315250079Scarl
316250079Scarl	net_softc.ntb = devclass_get_softc(devclass_find("ntb_hw"), 0);
317250079Scarl	if (net_softc.ntb == NULL) {
318255281Scarl		printf("ntb: Cannot find devclass\n");
319250079Scarl		return (ENXIO);
320250079Scarl	}
321250079Scarl
322250079Scarl	ntb_transport_init(net_softc.ntb);
323250079Scarl
324250079Scarl	ifp = net_softc.ifp = if_alloc(IFT_ETHER);
325250079Scarl	if (ifp == NULL) {
326250079Scarl		printf("ntb: cannot allocate ifnet structure\n");
327250079Scarl		return (ENOMEM);
328250079Scarl	}
329250079Scarl
330250079Scarl	net_softc.qp = ntb_transport_create_queue(ifp, net_softc.ntb,
331250079Scarl	    &handlers);
332250079Scarl	if_initname(ifp, "ntb", 0);
333250079Scarl	ifp->if_init = ntb_net_init;
334250079Scarl	ifp->if_softc = &net_softc;
335250079Scarl	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
336250079Scarl	ifp->if_ioctl = ntb_ioctl;
337250079Scarl	ifp->if_start = ntb_start;
338250079Scarl	IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
339250079Scarl	ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN;
340250079Scarl	IFQ_SET_READY(&ifp->if_snd);
341250079Scarl	create_random_local_eui48(net_softc.eaddr);
342250079Scarl	ether_ifattach(ifp, net_softc.eaddr);
343250079Scarl	ifp->if_capabilities = IFCAP_HWCSUM | IFCAP_JUMBO_MTU;
344250079Scarl	ifp->if_capenable = ifp->if_capabilities;
345250079Scarl
346250079Scarl	ntb_transport_link_up(net_softc.qp);
347250079Scarl	net_softc.bufsize = ntb_transport_max_size(net_softc.qp) +
348250079Scarl	    sizeof(struct ether_header);
349250079Scarl	return (0);
350250079Scarl}
351250079Scarl
352250079Scarlstatic int
353289209Scemntb_teardown_interface(void)
354250079Scarl{
355250079Scarl
356255280Scarl	if (net_softc.qp != NULL)
357255280Scarl		ntb_transport_link_down(net_softc.qp);
358250079Scarl
359255280Scarl	if (net_softc.ifp != NULL) {
360255280Scarl		ether_ifdetach(net_softc.ifp);
361255280Scarl		if_free(net_softc.ifp);
362255280Scarl	}
363250079Scarl
364255280Scarl	if (net_softc.qp != NULL) {
365255280Scarl		ntb_transport_free_queue(net_softc.qp);
366255280Scarl		ntb_transport_free(&net_softc);
367255280Scarl	}
368255280Scarl
369250079Scarl	return (0);
370250079Scarl}
371250079Scarl
372250079Scarl/* Network device interface */
373250079Scarl
374250079Scarlstatic void
375250079Scarlntb_net_init(void *arg)
376250079Scarl{
377250079Scarl	struct ntb_netdev *ntb_softc = arg;
378250079Scarl	struct ifnet *ifp = ntb_softc->ifp;
379250079Scarl
380250079Scarl	ifp->if_drv_flags |= IFF_DRV_RUNNING;
381250079Scarl	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
382250079Scarl	ifp->if_flags |= IFF_UP;
383250079Scarl	if_link_state_change(ifp, LINK_STATE_UP);
384250079Scarl}
385250079Scarl
386250079Scarlstatic int
387250079Scarlntb_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
388250079Scarl{
389250079Scarl	struct ntb_netdev *nt = ifp->if_softc;
390250079Scarl	struct ifreq *ifr = (struct ifreq *)data;
391250079Scarl	int error = 0;
392250079Scarl
393250079Scarl	switch (command) {
394250079Scarl	case SIOCSIFMTU:
395250079Scarl	    {
396250079Scarl		if (ifr->ifr_mtu > ntb_transport_max_size(nt->qp) -
397250079Scarl		    ETHER_HDR_LEN - ETHER_CRC_LEN) {
398250079Scarl			error = EINVAL;
399250079Scarl			break;
400250079Scarl		}
401250079Scarl
402250079Scarl		ifp->if_mtu = ifr->ifr_mtu;
403250079Scarl		break;
404250079Scarl	    }
405250079Scarl	default:
406250079Scarl		error = ether_ioctl(ifp, command, data);
407250079Scarl		break;
408250079Scarl	}
409250079Scarl
410250079Scarl	return (error);
411250079Scarl}
412250079Scarl
413250079Scarl
414250079Scarlstatic void
415250079Scarlntb_start(struct ifnet *ifp)
416250079Scarl{
417250079Scarl	struct mbuf *m_head;
418250079Scarl	struct ntb_netdev *nt = ifp->if_softc;
419250079Scarl	int rc;
420250079Scarl
421250079Scarl	mtx_lock(&nt->tx_lock);
422250079Scarl	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
423250079Scarl	CTR0(KTR_NTB, "TX: ntb_start");
424250079Scarl	while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) {
425250079Scarl		IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
426250079Scarl		CTR1(KTR_NTB, "TX: start mbuf %p", m_head);
427250079Scarl		rc = ntb_transport_tx_enqueue(nt->qp, m_head, m_head,
428250079Scarl			     m_length(m_head, NULL));
429250079Scarl		if (rc != 0) {
430250079Scarl			CTR1(KTR_NTB,
431255281Scarl			    "TX: could not tx mbuf %p. Returning to snd q",
432250079Scarl			    m_head);
433250079Scarl			if (rc == EAGAIN) {
434250079Scarl				ifp->if_drv_flags |= IFF_DRV_OACTIVE;
435250079Scarl				IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
436250079Scarl				callout_reset(&nt->qp->queue_full, hz / 1000,
437250079Scarl				    ntb_qp_full, ifp);
438250079Scarl			}
439250079Scarl			break;
440250079Scarl		}
441250079Scarl
442250079Scarl	}
443250079Scarl	mtx_unlock(&nt->tx_lock);
444250079Scarl}
445250079Scarl
446250079Scarl/* Network Device Callbacks */
447250079Scarlstatic void
448250079Scarlntb_net_tx_handler(struct ntb_transport_qp *qp, void *qp_data, void *data,
449250079Scarl    int len)
450250079Scarl{
451250079Scarl
452250079Scarl	m_freem(data);
453250079Scarl	CTR1(KTR_NTB, "TX: tx_handler freeing mbuf %p", data);
454250079Scarl}
455250079Scarl
456250079Scarlstatic void
457250079Scarlntb_net_rx_handler(struct ntb_transport_qp *qp, void *qp_data, void *data,
458250079Scarl    int len)
459250079Scarl{
460250079Scarl	struct mbuf *m = data;
461250079Scarl	struct ifnet *ifp = qp_data;
462250079Scarl
463250079Scarl	CTR0(KTR_NTB, "RX: rx handler");
464250079Scarl	(*ifp->if_input)(ifp, m);
465250079Scarl}
466250079Scarl
467250079Scarlstatic void
468289340Scemntb_net_event_handler(void *data, enum ntb_link_event status)
469250079Scarl{
470289340Scem	struct ifnet *ifp;
471250079Scarl
472289340Scem	ifp = data;
473289340Scem	(void)ifp;
474289340Scem
475289340Scem	/* XXX The Linux driver munges with the carrier status here. */
476289340Scem
477289340Scem	switch (status) {
478289340Scem	case NTB_LINK_DOWN:
479289340Scem		break;
480289340Scem	case NTB_LINK_UP:
481289340Scem		break;
482289340Scem	default:
483289340Scem		panic("Bogus ntb_link_event %u\n", status);
484289340Scem	}
485250079Scarl}
486250079Scarl
487250079Scarl/* Transport Init and teardown */
488250079Scarl
489250079Scarlstatic int
490250079Scarlntb_transport_init(struct ntb_softc *ntb)
491250079Scarl{
492250079Scarl	struct ntb_netdev *nt = &net_softc;
493250079Scarl	int rc, i;
494250079Scarl
495250079Scarl	nt->max_qps = max_num_clients;
496250079Scarl	ntb_register_transport(ntb, nt);
497250079Scarl	mtx_init(&nt->tx_lock, "ntb transport tx", NULL, MTX_DEF);
498250079Scarl	mtx_init(&nt->rx_lock, "ntb transport rx", NULL, MTX_DEF);
499250079Scarl
500250079Scarl	nt->qps = malloc(nt->max_qps * sizeof(struct ntb_transport_qp),
501250079Scarl			  M_NTB_IF, M_WAITOK|M_ZERO);
502250079Scarl
503250079Scarl	nt->qp_bitmap = ((uint64_t) 1 << nt->max_qps) - 1;
504250079Scarl
505250079Scarl	for (i = 0; i < nt->max_qps; i++)
506250079Scarl		ntb_transport_init_queue(nt, i);
507250079Scarl
508250079Scarl	callout_init(&nt->link_work, 0);
509250079Scarl
510250079Scarl	rc = ntb_register_event_callback(ntb,
511250079Scarl					 ntb_transport_event_callback);
512250079Scarl	if (rc != 0)
513250079Scarl		goto err;
514250079Scarl
515255268Scarl	if (ntb_query_link_status(ntb)) {
516255268Scarl		if (bootverbose)
517255268Scarl			device_printf(ntb_get_device(ntb), "link up\n");
518250079Scarl		callout_reset(&nt->link_work, 0, ntb_transport_link_work, nt);
519255268Scarl	}
520250079Scarl
521250079Scarl	return (0);
522250079Scarl
523250079Scarlerr:
524250079Scarl	free(nt->qps, M_NTB_IF);
525250079Scarl	ntb_unregister_transport(ntb);
526250079Scarl	return (rc);
527250079Scarl}
528250079Scarl
529250079Scarlstatic void
530250079Scarlntb_transport_free(void *transport)
531250079Scarl{
532250079Scarl	struct ntb_netdev *nt = transport;
533250079Scarl	struct ntb_softc *ntb = nt->ntb;
534250079Scarl	int i;
535250079Scarl
536289273Scem	ntb_transport_link_cleanup(nt);
537250079Scarl
538250079Scarl	callout_drain(&nt->link_work);
539250079Scarl
540255281Scarl	/* verify that all the qps are freed */
541250079Scarl	for (i = 0; i < nt->max_qps; i++)
542250079Scarl		if (!test_bit(i, &nt->qp_bitmap))
543250079Scarl			ntb_transport_free_queue(&nt->qps[i]);
544250079Scarl
545250079Scarl	ntb_unregister_event_callback(ntb);
546250079Scarl
547250079Scarl	for (i = 0; i < NTB_NUM_MW; i++)
548289153Scem		ntb_free_mw(nt, i);
549250079Scarl
550250079Scarl	free(nt->qps, M_NTB_IF);
551250079Scarl	ntb_unregister_transport(ntb);
552250079Scarl}
553250079Scarl
554250079Scarlstatic void
555250079Scarlntb_transport_init_queue(struct ntb_netdev *nt, unsigned int qp_num)
556250079Scarl{
557250079Scarl	struct ntb_transport_qp *qp;
558250079Scarl	unsigned int num_qps_mw, tx_size;
559250079Scarl	uint8_t mw_num = QP_TO_MW(qp_num);
560250079Scarl
561250079Scarl	qp = &nt->qps[qp_num];
562250079Scarl	qp->qp_num = qp_num;
563250079Scarl	qp->transport = nt;
564250079Scarl	qp->ntb = nt->ntb;
565250079Scarl	qp->qp_link = NTB_LINK_DOWN;
566250079Scarl	qp->client_ready = NTB_LINK_DOWN;
567250079Scarl	qp->event_handler = NULL;
568250079Scarl
569289345Scem	if (nt->max_qps % NTB_NUM_MW && mw_num + 1 < nt->max_qps / NTB_NUM_MW)
570250079Scarl		num_qps_mw = nt->max_qps / NTB_NUM_MW + 1;
571250079Scarl	else
572250079Scarl		num_qps_mw = nt->max_qps / NTB_NUM_MW;
573250079Scarl
574250079Scarl	tx_size = (unsigned int) ntb_get_mw_size(qp->ntb, mw_num) / num_qps_mw;
575250079Scarl	qp->rx_info = (struct ntb_rx_info *)
576250079Scarl	    ((char *)ntb_get_mw_vbase(qp->ntb, mw_num) +
577250079Scarl	    (qp_num / NTB_NUM_MW * tx_size));
578250079Scarl	tx_size -= sizeof(struct ntb_rx_info);
579250079Scarl
580289152Scem	qp->tx_mw = qp->rx_info + 1;
581289156Scem	/* Due to house-keeping, there must be at least 2 buffs */
582250079Scarl	qp->tx_max_frame = min(transport_mtu + sizeof(struct ntb_payload_header),
583289156Scem	    tx_size / 2);
584250079Scarl	qp->tx_max_entry = tx_size / qp->tx_max_frame;
585250079Scarl
586250079Scarl	callout_init(&qp->link_work, 0);
587283291Sjkim	callout_init(&qp->queue_full, 1);
588283291Sjkim	callout_init(&qp->rx_full, 1);
589250079Scarl
590250079Scarl	mtx_init(&qp->ntb_rx_pend_q_lock, "ntb rx pend q", NULL, MTX_SPIN);
591250079Scarl	mtx_init(&qp->ntb_rx_free_q_lock, "ntb rx free q", NULL, MTX_SPIN);
592250079Scarl	mtx_init(&qp->ntb_tx_free_q_lock, "ntb tx free q", NULL, MTX_SPIN);
593250079Scarl	TASK_INIT(&qp->rx_completion_task, 0, ntb_rx_completion_task, qp);
594250079Scarl
595250079Scarl	STAILQ_INIT(&qp->rx_pend_q);
596250079Scarl	STAILQ_INIT(&qp->rx_free_q);
597250079Scarl	STAILQ_INIT(&qp->tx_free_q);
598250079Scarl}
599250079Scarl
600250079Scarlstatic void
601250079Scarlntb_transport_free_queue(struct ntb_transport_qp *qp)
602250079Scarl{
603250079Scarl	struct ntb_queue_entry *entry;
604250079Scarl
605250079Scarl	if (qp == NULL)
606250079Scarl		return;
607250079Scarl
608250079Scarl	callout_drain(&qp->link_work);
609250079Scarl
610250079Scarl	ntb_unregister_db_callback(qp->ntb, qp->qp_num);
611250079Scarl
612250079Scarl	while ((entry = ntb_list_rm(&qp->ntb_rx_free_q_lock, &qp->rx_free_q)))
613250079Scarl		free(entry, M_NTB_IF);
614250079Scarl
615250079Scarl	while ((entry = ntb_list_rm(&qp->ntb_rx_pend_q_lock, &qp->rx_pend_q)))
616250079Scarl		free(entry, M_NTB_IF);
617250079Scarl
618250079Scarl	while ((entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q)))
619250079Scarl		free(entry, M_NTB_IF);
620250079Scarl
621250079Scarl	set_bit(qp->qp_num, &qp->transport->qp_bitmap);
622250079Scarl}
623250079Scarl
624250079Scarl/**
625250079Scarl * ntb_transport_create_queue - Create a new NTB transport layer queue
626250079Scarl * @rx_handler: receive callback function
627250079Scarl * @tx_handler: transmit callback function
628250079Scarl * @event_handler: event callback function
629250079Scarl *
630250079Scarl * Create a new NTB transport layer queue and provide the queue with a callback
631250079Scarl * routine for both transmit and receive.  The receive callback routine will be
632250079Scarl * used to pass up data when the transport has received it on the queue.   The
633250079Scarl * transmit callback routine will be called when the transport has completed the
634250079Scarl * transmission of the data on the queue and the data is ready to be freed.
635250079Scarl *
636250079Scarl * RETURNS: pointer to newly created ntb_queue, NULL on error.
637250079Scarl */
638250079Scarlstatic struct ntb_transport_qp *
639250079Scarlntb_transport_create_queue(void *data, struct ntb_softc *pdev,
640250079Scarl    const struct ntb_queue_handlers *handlers)
641250079Scarl{
642250079Scarl	struct ntb_queue_entry *entry;
643250079Scarl	struct ntb_transport_qp *qp;
644250079Scarl	struct ntb_netdev *nt;
645250079Scarl	unsigned int free_queue;
646250079Scarl	int rc, i;
647250079Scarl
648250079Scarl	nt = ntb_find_transport(pdev);
649250079Scarl	if (nt == NULL)
650250079Scarl		goto err;
651250079Scarl
652250079Scarl	free_queue = ffs(nt->qp_bitmap);
653250079Scarl	if (free_queue == 0)
654250079Scarl		goto err;
655250079Scarl
656250079Scarl	/* decrement free_queue to make it zero based */
657250079Scarl	free_queue--;
658250079Scarl
659250079Scarl	clear_bit(free_queue, &nt->qp_bitmap);
660250079Scarl
661250079Scarl	qp = &nt->qps[free_queue];
662250079Scarl	qp->cb_data = data;
663250079Scarl	qp->rx_handler = handlers->rx_handler;
664250079Scarl	qp->tx_handler = handlers->tx_handler;
665250079Scarl	qp->event_handler = handlers->event_handler;
666250079Scarl
667250079Scarl	for (i = 0; i < NTB_QP_DEF_NUM_ENTRIES; i++) {
668250079Scarl		entry = malloc(sizeof(struct ntb_queue_entry), M_NTB_IF,
669250079Scarl		    M_WAITOK|M_ZERO);
670250079Scarl		entry->cb_data = nt->ifp;
671250079Scarl		entry->buf = NULL;
672250079Scarl		entry->len = transport_mtu;
673250079Scarl		ntb_list_add(&qp->ntb_rx_pend_q_lock, entry, &qp->rx_pend_q);
674250079Scarl	}
675250079Scarl
676250079Scarl	for (i = 0; i < NTB_QP_DEF_NUM_ENTRIES; i++) {
677250079Scarl		entry = malloc(sizeof(struct ntb_queue_entry), M_NTB_IF,
678250079Scarl		    M_WAITOK|M_ZERO);
679250079Scarl		ntb_list_add(&qp->ntb_tx_free_q_lock, entry, &qp->tx_free_q);
680250079Scarl	}
681250079Scarl
682250079Scarl	rc = ntb_register_db_callback(qp->ntb, free_queue, qp,
683250079Scarl				      ntb_transport_rxc_db);
684250079Scarl	if (rc != 0)
685250079Scarl		goto err1;
686250079Scarl
687250079Scarl	return (qp);
688250079Scarl
689250079Scarlerr1:
690250079Scarl	while ((entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q)))
691250079Scarl		free(entry, M_NTB_IF);
692250079Scarl	while ((entry = ntb_list_rm(&qp->ntb_rx_free_q_lock, &qp->rx_free_q)))
693250079Scarl		free(entry, M_NTB_IF);
694250079Scarl	set_bit(free_queue, &nt->qp_bitmap);
695250079Scarlerr:
696250079Scarl	return (NULL);
697250079Scarl}
698250079Scarl
699250079Scarl/**
700250079Scarl * ntb_transport_link_up - Notify NTB transport of client readiness to use queue
701250079Scarl * @qp: NTB transport layer queue to be enabled
702250079Scarl *
703250079Scarl * Notify NTB transport layer of client readiness to use queue
704250079Scarl */
705250079Scarlstatic void
706250079Scarlntb_transport_link_up(struct ntb_transport_qp *qp)
707250079Scarl{
708250079Scarl
709250079Scarl	if (qp == NULL)
710250079Scarl		return;
711250079Scarl
712250079Scarl	qp->client_ready = NTB_LINK_UP;
713255268Scarl	if (bootverbose)
714255268Scarl		device_printf(ntb_get_device(qp->ntb), "qp client ready\n");
715250079Scarl
716250079Scarl	if (qp->transport->transport_link == NTB_LINK_UP)
717250079Scarl		callout_reset(&qp->link_work, 0, ntb_qp_link_work, qp);
718250079Scarl}
719250079Scarl
720250079Scarl
721250079Scarl
722250079Scarl/* Transport Tx */
723250079Scarl
724250079Scarl/**
725250079Scarl * ntb_transport_tx_enqueue - Enqueue a new NTB queue entry
726250079Scarl * @qp: NTB transport layer queue the entry is to be enqueued on
727250079Scarl * @cb: per buffer pointer for callback function to use
728250079Scarl * @data: pointer to data buffer that will be sent
729250079Scarl * @len: length of the data buffer
730250079Scarl *
731250079Scarl * Enqueue a new transmit buffer onto the transport queue from which a NTB
732289266Scem * payload will be transmitted.  This assumes that a lock is being held to
733250079Scarl * serialize access to the qp.
734250079Scarl *
735250079Scarl * RETURNS: An appropriate ERRNO error value on error, or zero for success.
736250079Scarl */
737250079Scarlstatic int
738250079Scarlntb_transport_tx_enqueue(struct ntb_transport_qp *qp, void *cb, void *data,
739250079Scarl    unsigned int len)
740250079Scarl{
741250079Scarl	struct ntb_queue_entry *entry;
742250079Scarl	int rc;
743250079Scarl
744250079Scarl	if (qp == NULL || qp->qp_link != NTB_LINK_UP || len == 0) {
745250079Scarl		CTR0(KTR_NTB, "TX: link not up");
746250079Scarl		return (EINVAL);
747250079Scarl	}
748250079Scarl
749250079Scarl	entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q);
750250079Scarl	if (entry == NULL) {
751255281Scarl		CTR0(KTR_NTB, "TX: could not get entry from tx_free_q");
752250079Scarl		return (ENOMEM);
753250079Scarl	}
754250079Scarl	CTR1(KTR_NTB, "TX: got entry %p from tx_free_q", entry);
755250079Scarl
756250079Scarl	entry->cb_data = cb;
757250079Scarl	entry->buf = data;
758250079Scarl	entry->len = len;
759250079Scarl	entry->flags = 0;
760250079Scarl
761250079Scarl	rc = ntb_process_tx(qp, entry);
762250079Scarl	if (rc != 0) {
763250079Scarl		ntb_list_add(&qp->ntb_tx_free_q_lock, entry, &qp->tx_free_q);
764250079Scarl		CTR1(KTR_NTB,
765250079Scarl		    "TX: process_tx failed. Returning entry %p to tx_free_q",
766250079Scarl		    entry);
767250079Scarl	}
768250079Scarl	return (rc);
769250079Scarl}
770250079Scarl
771250079Scarlstatic int
772250079Scarlntb_process_tx(struct ntb_transport_qp *qp, struct ntb_queue_entry *entry)
773250079Scarl{
774250079Scarl	void *offset;
775250079Scarl
776250079Scarl	offset = (char *)qp->tx_mw + qp->tx_max_frame * qp->tx_index;
777250079Scarl	CTR3(KTR_NTB,
778250079Scarl	    "TX: process_tx: tx_pkts=%u, tx_index=%u, remote entry=%u",
779250079Scarl	    qp->tx_pkts, qp->tx_index, qp->remote_rx_info->entry);
780250079Scarl	if (qp->tx_index == qp->remote_rx_info->entry) {
781250079Scarl		CTR0(KTR_NTB, "TX: ring full");
782250079Scarl		qp->tx_ring_full++;
783250079Scarl		return (EAGAIN);
784250079Scarl	}
785250079Scarl
786250079Scarl	if (entry->len > qp->tx_max_frame - sizeof(struct ntb_payload_header)) {
787250079Scarl		if (qp->tx_handler != NULL)
788250079Scarl			qp->tx_handler(qp, qp->cb_data, entry->buf,
789250079Scarl				       EIO);
790250079Scarl
791250079Scarl		ntb_list_add(&qp->ntb_tx_free_q_lock, entry, &qp->tx_free_q);
792250079Scarl		CTR1(KTR_NTB,
793250079Scarl		    "TX: frame too big. returning entry %p to tx_free_q",
794250079Scarl		    entry);
795250079Scarl		return (0);
796250079Scarl	}
797250079Scarl	CTR2(KTR_NTB, "TX: copying entry %p to offset %p", entry, offset);
798250079Scarl	ntb_tx_copy_task(qp, entry, offset);
799250079Scarl
800250079Scarl	qp->tx_index++;
801250079Scarl	qp->tx_index %= qp->tx_max_entry;
802250079Scarl
803250079Scarl	qp->tx_pkts++;
804250079Scarl
805250079Scarl	return (0);
806250079Scarl}
807250079Scarl
808250079Scarlstatic void
809250079Scarlntb_tx_copy_task(struct ntb_transport_qp *qp, struct ntb_queue_entry *entry,
810250079Scarl    void *offset)
811250079Scarl{
812250079Scarl	struct ntb_payload_header *hdr;
813250079Scarl
814250079Scarl	CTR2(KTR_NTB, "TX: copying %d bytes to offset %p", entry->len, offset);
815250079Scarl	if (entry->buf != NULL)
816250079Scarl		m_copydata((struct mbuf *)entry->buf, 0, entry->len, offset);
817250079Scarl
818250079Scarl	hdr = (struct ntb_payload_header *)((char *)offset + qp->tx_max_frame -
819250079Scarl	    sizeof(struct ntb_payload_header));
820250079Scarl	hdr->len = entry->len; /* TODO: replace with bus_space_write */
821250079Scarl	hdr->ver = qp->tx_pkts; /* TODO: replace with bus_space_write */
822250079Scarl	wmb();
823250079Scarl	/* TODO: replace with bus_space_write */
824250079Scarl	hdr->flags = entry->flags | IF_NTB_DESC_DONE_FLAG;
825250079Scarl
826289255Scem	ntb_ring_doorbell(qp->ntb, qp->qp_num);
827250079Scarl
828289341Scem	/*
829250079Scarl	 * The entry length can only be zero if the packet is intended to be a
830250079Scarl	 * "link down" or similar.  Since no payload is being sent in these
831250079Scarl	 * cases, there is nothing to add to the completion queue.
832250079Scarl	 */
833250079Scarl	if (entry->len > 0) {
834250079Scarl		qp->tx_bytes += entry->len;
835250079Scarl
836250079Scarl		if (qp->tx_handler)
837250079Scarl			qp->tx_handler(qp, qp->cb_data, entry->cb_data,
838250079Scarl				       entry->len);
839250079Scarl	}
840250079Scarl
841250079Scarl	CTR2(KTR_NTB,
842250079Scarl	    "TX: entry %p sent. hdr->ver = %d, Returning to tx_free_q", entry,
843250079Scarl	    hdr->ver);
844250079Scarl	ntb_list_add(&qp->ntb_tx_free_q_lock, entry, &qp->tx_free_q);
845250079Scarl}
846250079Scarl
847250079Scarlstatic void
848250079Scarlntb_qp_full(void *arg)
849250079Scarl{
850250079Scarl
851250079Scarl	CTR0(KTR_NTB, "TX: qp_full callout");
852250079Scarl	ntb_start(arg);
853250079Scarl}
854250079Scarl
855250079Scarl/* Transport Rx */
856250079Scarlstatic void
857250079Scarlntb_rx_pendq_full(void *arg)
858250079Scarl{
859250079Scarl
860250079Scarl	CTR0(KTR_NTB, "RX: ntb_rx_pendq_full callout");
861289281Scem	ntb_transport_rxc_db(arg, 0);
862250079Scarl}
863250079Scarl
864289281Scemstatic int
865289281Scemntb_transport_rxc_db(void *arg, int dummy __unused)
866250079Scarl{
867289281Scem	struct ntb_transport_qp *qp = arg;
868289157Scem	uint64_t i;
869289157Scem	int rc;
870250079Scarl
871289341Scem	/*
872250079Scarl	 * Limit the number of packets processed in a single interrupt to
873250079Scarl	 * provide fairness to others
874250079Scarl	 */
875250079Scarl	mtx_lock(&qp->transport->rx_lock);
876250079Scarl	CTR0(KTR_NTB, "RX: transport_rx");
877289281Scem	for (i = 0; i < MIN(qp->rx_max_entry, INT_MAX); i++) {
878250079Scarl		rc = ntb_process_rxc(qp);
879250079Scarl		if (rc != 0) {
880250079Scarl			CTR0(KTR_NTB, "RX: process_rxc failed");
881250079Scarl			break;
882250079Scarl		}
883250079Scarl	}
884250079Scarl	mtx_unlock(&qp->transport->rx_lock);
885289281Scem
886289281Scem	return ((int)i);
887250079Scarl}
888250079Scarl
889250079Scarlstatic int
890250079Scarlntb_process_rxc(struct ntb_transport_qp *qp)
891250079Scarl{
892250079Scarl	struct ntb_payload_header *hdr;
893250079Scarl	struct ntb_queue_entry *entry;
894250079Scarl	void *offset;
895250079Scarl
896250079Scarl	offset = (void *)
897250079Scarl	    ((char *)qp->rx_buff + qp->rx_max_frame * qp->rx_index);
898250079Scarl	hdr = (void *)
899250079Scarl	    ((char *)offset + qp->rx_max_frame -
900250079Scarl		sizeof(struct ntb_payload_header));
901250079Scarl
902250079Scarl	CTR1(KTR_NTB, "RX: process_rxc rx_index = %u", qp->rx_index);
903250079Scarl	entry = ntb_list_rm(&qp->ntb_rx_pend_q_lock, &qp->rx_pend_q);
904250079Scarl	if (entry == NULL) {
905250079Scarl		qp->rx_err_no_buf++;
906250079Scarl		CTR0(KTR_NTB, "RX: No entries in rx_pend_q");
907250079Scarl		return (ENOMEM);
908250079Scarl	}
909250079Scarl	callout_stop(&qp->rx_full);
910250079Scarl	CTR1(KTR_NTB, "RX: rx entry %p from rx_pend_q", entry);
911250079Scarl
912250079Scarl	if ((hdr->flags & IF_NTB_DESC_DONE_FLAG) == 0) {
913250079Scarl		CTR1(KTR_NTB,
914250079Scarl		    "RX: hdr not done. Returning entry %p to rx_pend_q", entry);
915250079Scarl		ntb_list_add(&qp->ntb_rx_pend_q_lock, entry, &qp->rx_pend_q);
916250079Scarl		qp->rx_ring_empty++;
917250079Scarl		return (EAGAIN);
918250079Scarl	}
919250079Scarl
920250079Scarl	if (hdr->ver != (uint32_t) qp->rx_pkts) {
921250079Scarl		CTR3(KTR_NTB,"RX: ver != rx_pkts (%x != %lx). "
922250079Scarl		    "Returning entry %p to rx_pend_q", hdr->ver, qp->rx_pkts,
923250079Scarl		    entry);
924250079Scarl		ntb_list_add(&qp->ntb_rx_pend_q_lock, entry, &qp->rx_pend_q);
925250079Scarl		qp->rx_err_ver++;
926250079Scarl		return (EIO);
927250079Scarl	}
928250079Scarl
929250079Scarl	if ((hdr->flags & IF_NTB_LINK_DOWN_FLAG) != 0) {
930250079Scarl		ntb_qp_link_down(qp);
931250079Scarl		CTR1(KTR_NTB,
932250079Scarl		    "RX: link down. adding entry %p back to rx_pend_q", entry);
933250079Scarl		ntb_list_add(&qp->ntb_rx_pend_q_lock, entry, &qp->rx_pend_q);
934250079Scarl		goto out;
935250079Scarl	}
936250079Scarl
937250079Scarl	if (hdr->len <= entry->len) {
938250079Scarl		entry->len = hdr->len;
939250079Scarl		ntb_rx_copy_task(qp, entry, offset);
940250079Scarl	} else {
941250079Scarl		CTR1(KTR_NTB,
942250079Scarl		    "RX: len too long. Returning entry %p to rx_pend_q", entry);
943250079Scarl		ntb_list_add(&qp->ntb_rx_pend_q_lock, entry, &qp->rx_pend_q);
944250079Scarl
945250079Scarl		qp->rx_err_oflow++;
946250079Scarl	}
947250079Scarl
948250079Scarl	qp->rx_bytes += hdr->len;
949250079Scarl	qp->rx_pkts++;
950250079Scarl	CTR1(KTR_NTB, "RX: received %ld rx_pkts", qp->rx_pkts);
951250079Scarl
952250079Scarl
953250079Scarlout:
954250079Scarl	/* Ensure that the data is globally visible before clearing the flag */
955250079Scarl	wmb();
956250079Scarl	hdr->flags = 0;
957250079Scarl	/* TODO: replace with bus_space_write */
958250079Scarl	qp->rx_info->entry = qp->rx_index;
959250079Scarl
960250079Scarl	qp->rx_index++;
961250079Scarl	qp->rx_index %= qp->rx_max_entry;
962250079Scarl
963250079Scarl	return (0);
964250079Scarl}
965250079Scarl
966250079Scarlstatic void
967250079Scarlntb_rx_copy_task(struct ntb_transport_qp *qp, struct ntb_queue_entry *entry,
968250079Scarl    void *offset)
969250079Scarl{
970250079Scarl	struct ifnet *ifp = entry->cb_data;
971250079Scarl	unsigned int len = entry->len;
972250079Scarl	struct mbuf *m;
973250079Scarl
974250079Scarl	CTR2(KTR_NTB, "RX: copying %d bytes from offset %p", len, offset);
975250079Scarl	m = m_devget(offset, len, 0, ifp, NULL);
976250079Scarl	m->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID;
977250079Scarl
978250079Scarl	entry->buf = (void *)m;
979250079Scarl
980250079Scarl	CTR2(KTR_NTB,
981250079Scarl	    "RX: copied entry %p to mbuf %p. Adding entry to rx_free_q", entry,
982250079Scarl	    m);
983250079Scarl	ntb_list_add(&qp->ntb_rx_free_q_lock, entry, &qp->rx_free_q);
984250079Scarl
985250079Scarl	taskqueue_enqueue(taskqueue_swi, &qp->rx_completion_task);
986250079Scarl}
987250079Scarl
988250079Scarlstatic void
989250079Scarlntb_rx_completion_task(void *arg, int pending)
990250079Scarl{
991250079Scarl	struct ntb_transport_qp *qp = arg;
992250079Scarl	struct mbuf *m;
993250079Scarl	struct ntb_queue_entry *entry;
994250079Scarl
995250079Scarl	CTR0(KTR_NTB, "RX: rx_completion_task");
996250079Scarl
997250079Scarl	while ((entry = ntb_list_rm(&qp->ntb_rx_free_q_lock, &qp->rx_free_q))) {
998250079Scarl		m = entry->buf;
999250079Scarl		CTR2(KTR_NTB, "RX: completing entry %p, mbuf %p", entry, m);
1000250079Scarl		if (qp->rx_handler && qp->client_ready == NTB_LINK_UP)
1001250079Scarl			qp->rx_handler(qp, qp->cb_data, m, entry->len);
1002250079Scarl
1003250079Scarl		entry->buf = NULL;
1004250079Scarl		entry->len = qp->transport->bufsize;
1005250079Scarl
1006250079Scarl		CTR1(KTR_NTB,"RX: entry %p removed from rx_free_q "
1007250079Scarl		    "and added to rx_pend_q", entry);
1008250079Scarl		ntb_list_add(&qp->ntb_rx_pend_q_lock, entry, &qp->rx_pend_q);
1009250079Scarl		if (qp->rx_err_no_buf > qp->last_rx_no_buf) {
1010250079Scarl			qp->last_rx_no_buf = qp->rx_err_no_buf;
1011250079Scarl			CTR0(KTR_NTB, "RX: could spawn rx task");
1012250079Scarl			callout_reset(&qp->rx_full, hz / 1000, ntb_rx_pendq_full,
1013250079Scarl			    qp);
1014250079Scarl		}
1015250079Scarl	}
1016250079Scarl}
1017250079Scarl
1018250079Scarl/* Link Event handler */
1019250079Scarlstatic void
1020250079Scarlntb_transport_event_callback(void *data, enum ntb_hw_event event)
1021250079Scarl{
1022250079Scarl	struct ntb_netdev *nt = data;
1023250079Scarl
1024250079Scarl	switch (event) {
1025250079Scarl	case NTB_EVENT_HW_LINK_UP:
1026255268Scarl		if (bootverbose)
1027255268Scarl			device_printf(ntb_get_device(nt->ntb), "HW link up\n");
1028250079Scarl		callout_reset(&nt->link_work, 0, ntb_transport_link_work, nt);
1029250079Scarl		break;
1030250079Scarl	case NTB_EVENT_HW_LINK_DOWN:
1031255268Scarl		if (bootverbose)
1032255268Scarl			device_printf(ntb_get_device(nt->ntb), "HW link down\n");
1033250079Scarl		ntb_transport_link_cleanup(nt);
1034250079Scarl		break;
1035250079Scarl	default:
1036250079Scarl		panic("ntb: Unknown NTB event");
1037250079Scarl	}
1038250079Scarl}
1039250079Scarl
1040250079Scarl/* Link bring up */
1041250079Scarlstatic void
1042250079Scarlntb_transport_link_work(void *arg)
1043250079Scarl{
1044250079Scarl	struct ntb_netdev *nt = arg;
1045250079Scarl	struct ntb_softc *ntb = nt->ntb;
1046250079Scarl	struct ntb_transport_qp *qp;
1047289153Scem	uint64_t val64;
1048289208Scem	uint32_t val, i, num_mw;
1049289208Scem	int rc;
1050250079Scarl
1051289208Scem	if (ntb_has_feature(ntb, NTB_REGS_THRU_MW))
1052289208Scem		num_mw = NTB_NUM_MW - 1;
1053289208Scem	else
1054289208Scem		num_mw = NTB_NUM_MW;
1055289208Scem
1056289153Scem	/* send the local info, in the opposite order of the way we read it */
1057289208Scem	for (i = 0; i < num_mw; i++) {
1058289153Scem		rc = ntb_write_remote_spad(ntb, IF_NTB_MW0_SZ_HIGH + (i * 2),
1059289259Scem		    (uint64_t)ntb_get_mw_size(ntb, i) >> 32);
1060289153Scem		if (rc != 0)
1061289153Scem			goto out;
1062250079Scarl
1063289153Scem		rc = ntb_write_remote_spad(ntb, IF_NTB_MW0_SZ_LOW + (i * 2),
1064289153Scem		    (uint32_t)ntb_get_mw_size(ntb, i));
1065289153Scem		if (rc != 0)
1066289153Scem			goto out;
1067289153Scem	}
1068250079Scarl
1069289208Scem	rc = ntb_write_remote_spad(ntb, IF_NTB_NUM_MWS, num_mw);
1070250079Scarl	if (rc != 0)
1071250079Scarl		goto out;
1072250079Scarl
1073250079Scarl	rc = ntb_write_remote_spad(ntb, IF_NTB_NUM_QPS, nt->max_qps);
1074250079Scarl	if (rc != 0)
1075250079Scarl		goto out;
1076250079Scarl
1077289153Scem	rc = ntb_write_remote_spad(ntb, IF_NTB_VERSION, NTB_TRANSPORT_VERSION);
1078250079Scarl	if (rc != 0)
1079250079Scarl		goto out;
1080250079Scarl
1081250079Scarl	/* Query the remote side for its info */
1082250079Scarl	rc = ntb_read_local_spad(ntb, IF_NTB_VERSION, &val);
1083250079Scarl	if (rc != 0)
1084250079Scarl		goto out;
1085250079Scarl
1086250079Scarl	if (val != NTB_TRANSPORT_VERSION)
1087250079Scarl		goto out;
1088250079Scarl
1089250079Scarl	rc = ntb_read_local_spad(ntb, IF_NTB_NUM_QPS, &val);
1090250079Scarl	if (rc != 0)
1091250079Scarl		goto out;
1092250079Scarl
1093250079Scarl	if (val != nt->max_qps)
1094250079Scarl		goto out;
1095250079Scarl
1096289153Scem	rc = ntb_read_local_spad(ntb, IF_NTB_NUM_MWS, &val);
1097250079Scarl	if (rc != 0)
1098250079Scarl		goto out;
1099250079Scarl
1100289208Scem	if (val != num_mw)
1101250079Scarl		goto out;
1102250079Scarl
1103289208Scem	for (i = 0; i < num_mw; i++) {
1104289153Scem		rc = ntb_read_local_spad(ntb, IF_NTB_MW0_SZ_HIGH + (i * 2),
1105289153Scem		    &val);
1106289153Scem		if (rc != 0)
1107289153Scem			goto free_mws;
1108250079Scarl
1109289153Scem		val64 = (uint64_t)val << 32;
1110250079Scarl
1111289153Scem		rc = ntb_read_local_spad(ntb, IF_NTB_MW0_SZ_LOW + (i * 2),
1112289153Scem		    &val);
1113289153Scem		if (rc != 0)
1114289153Scem			goto free_mws;
1115250079Scarl
1116289153Scem		val64 |= val;
1117250079Scarl
1118289153Scem		rc = ntb_set_mw(nt, i, val64);
1119289153Scem		if (rc != 0)
1120289153Scem			goto free_mws;
1121289153Scem	}
1122289153Scem
1123250079Scarl	nt->transport_link = NTB_LINK_UP;
1124255268Scarl	if (bootverbose)
1125255268Scarl		device_printf(ntb_get_device(ntb), "transport link up\n");
1126250079Scarl
1127250079Scarl	for (i = 0; i < nt->max_qps; i++) {
1128250079Scarl		qp = &nt->qps[i];
1129250079Scarl
1130250079Scarl		ntb_transport_setup_qp_mw(nt, i);
1131250079Scarl
1132250079Scarl		if (qp->client_ready == NTB_LINK_UP)
1133250079Scarl			callout_reset(&qp->link_work, 0, ntb_qp_link_work, qp);
1134250079Scarl	}
1135250079Scarl
1136250079Scarl	return;
1137250079Scarl
1138289153Scemfree_mws:
1139289153Scem	for (i = 0; i < NTB_NUM_MW; i++)
1140289153Scem		ntb_free_mw(nt, i);
1141250079Scarlout:
1142250079Scarl	if (ntb_query_link_status(ntb))
1143250079Scarl		callout_reset(&nt->link_work,
1144289153Scem		    NTB_LINK_DOWN_TIMEOUT * hz / 1000, ntb_transport_link_work, nt);
1145250079Scarl}
1146250079Scarl
1147250079Scarlstatic int
1148250079Scarlntb_set_mw(struct ntb_netdev *nt, int num_mw, unsigned int size)
1149250079Scarl{
1150250079Scarl	struct ntb_transport_mw *mw = &nt->mw[num_mw];
1151250079Scarl
1152289154Scem	/* No need to re-setup */
1153289154Scem	if (mw->size == size)
1154289154Scem		return (0);
1155289154Scem
1156289154Scem	if (mw->size != 0)
1157289154Scem		ntb_free_mw(nt, num_mw);
1158289154Scem
1159250079Scarl	/* Alloc memory for receiving data.  Must be 4k aligned */
1160250079Scarl	mw->size = size;
1161250079Scarl
1162250079Scarl	mw->virt_addr = contigmalloc(mw->size, M_NTB_IF, M_ZERO, 0,
1163250079Scarl	    BUS_SPACE_MAXADDR, mw->size, 0);
1164250079Scarl	if (mw->virt_addr == NULL) {
1165289154Scem		mw->size = 0;
1166289346Scem		printf("ntb: Unable to allocate MW buffer of size %zu\n",
1167289346Scem		    mw->size);
1168250079Scarl		return (ENOMEM);
1169250079Scarl	}
1170250079Scarl	/* TODO: replace with bus_space_* functions */
1171250079Scarl	mw->dma_addr = vtophys(mw->virt_addr);
1172250079Scarl
1173289346Scem	/*
1174289346Scem	 * Ensure that the allocation from contigmalloc is aligned as
1175289346Scem	 * requested.  XXX: This may not be needed -- brought in for parity
1176289346Scem	 * with the Linux driver.
1177289346Scem	 */
1178289346Scem	if (mw->dma_addr % size != 0) {
1179289346Scem		device_printf(ntb_get_device(nt->ntb),
1180289346Scem		    "DMA memory 0x%jx not aligned to BAR size 0x%x\n",
1181289346Scem		    (uintmax_t)mw->dma_addr, size);
1182289346Scem		ntb_free_mw(nt, num_mw);
1183289346Scem		return (ENOMEM);
1184289346Scem	}
1185289346Scem
1186250079Scarl	/* Notify HW the memory location of the receive buffer */
1187250079Scarl	ntb_set_mw_addr(nt->ntb, num_mw, mw->dma_addr);
1188250079Scarl
1189250079Scarl	return (0);
1190250079Scarl}
1191250079Scarl
1192250079Scarlstatic void
1193289153Scemntb_free_mw(struct ntb_netdev *nt, int num_mw)
1194289153Scem{
1195289153Scem	struct ntb_transport_mw *mw = &nt->mw[num_mw];
1196289153Scem
1197289153Scem	if (mw->virt_addr == NULL)
1198289153Scem		return;
1199289153Scem
1200289153Scem	contigfree(mw->virt_addr, mw->size, M_NTB_IF);
1201289153Scem	mw->virt_addr = NULL;
1202289153Scem}
1203289153Scem
1204289153Scemstatic void
1205250079Scarlntb_transport_setup_qp_mw(struct ntb_netdev *nt, unsigned int qp_num)
1206250079Scarl{
1207250079Scarl	struct ntb_transport_qp *qp = &nt->qps[qp_num];
1208250079Scarl	void *offset;
1209250079Scarl	unsigned int rx_size, num_qps_mw;
1210250079Scarl	uint8_t mw_num = QP_TO_MW(qp_num);
1211250079Scarl	unsigned int i;
1212250079Scarl
1213289345Scem	if (nt->max_qps % NTB_NUM_MW && mw_num + 1 < nt->max_qps / NTB_NUM_MW)
1214250079Scarl		num_qps_mw = nt->max_qps / NTB_NUM_MW + 1;
1215250079Scarl	else
1216250079Scarl		num_qps_mw = nt->max_qps / NTB_NUM_MW;
1217250079Scarl
1218250079Scarl	rx_size = (unsigned int) nt->mw[mw_num].size / num_qps_mw;
1219250079Scarl	qp->remote_rx_info = (void *)((uint8_t *)nt->mw[mw_num].virt_addr +
1220250079Scarl			     (qp_num / NTB_NUM_MW * rx_size));
1221250079Scarl	rx_size -= sizeof(struct ntb_rx_info);
1222250079Scarl
1223289152Scem	qp->rx_buff = qp->remote_rx_info + 1;
1224289156Scem	/* Due to house-keeping, there must be at least 2 buffs */
1225250079Scarl	qp->rx_max_frame = min(transport_mtu + sizeof(struct ntb_payload_header),
1226289156Scem	    rx_size / 2);
1227250079Scarl	qp->rx_max_entry = rx_size / qp->rx_max_frame;
1228250079Scarl	qp->rx_index = 0;
1229250079Scarl
1230289156Scem	qp->remote_rx_info->entry = qp->rx_max_entry - 1;
1231250079Scarl
1232250079Scarl	/* setup the hdr offsets with 0's */
1233250079Scarl	for (i = 0; i < qp->rx_max_entry; i++) {
1234250079Scarl		offset = (void *)((uint8_t *)qp->rx_buff +
1235250079Scarl		    qp->rx_max_frame * (i + 1) -
1236250079Scarl		    sizeof(struct ntb_payload_header));
1237250079Scarl		memset(offset, 0, sizeof(struct ntb_payload_header));
1238250079Scarl	}
1239250079Scarl
1240250079Scarl	qp->rx_pkts = 0;
1241250079Scarl	qp->tx_pkts = 0;
1242289155Scem	qp->tx_index = 0;
1243250079Scarl}
1244250079Scarl
1245250079Scarlstatic void
1246250079Scarlntb_qp_link_work(void *arg)
1247250079Scarl{
1248250079Scarl	struct ntb_transport_qp *qp = arg;
1249250079Scarl	struct ntb_softc *ntb = qp->ntb;
1250250079Scarl	struct ntb_netdev *nt = qp->transport;
1251250079Scarl	int rc, val;
1252250079Scarl
1253250079Scarl
1254250079Scarl	rc = ntb_read_remote_spad(ntb, IF_NTB_QP_LINKS, &val);
1255250079Scarl	if (rc != 0)
1256250079Scarl		return;
1257250079Scarl
1258250079Scarl	rc = ntb_write_remote_spad(ntb, IF_NTB_QP_LINKS, val | 1 << qp->qp_num);
1259250079Scarl
1260250079Scarl	/* query remote spad for qp ready bits */
1261250079Scarl	rc = ntb_read_local_spad(ntb, IF_NTB_QP_LINKS, &val);
1262250079Scarl
1263250079Scarl	/* See if the remote side is up */
1264250079Scarl	if ((1 << qp->qp_num & val) != 0) {
1265250079Scarl		qp->qp_link = NTB_LINK_UP;
1266250079Scarl		if (qp->event_handler != NULL)
1267250079Scarl			qp->event_handler(qp->cb_data, NTB_LINK_UP);
1268255268Scarl		if (bootverbose)
1269255268Scarl			device_printf(ntb_get_device(ntb), "qp link up\n");
1270250079Scarl	} else if (nt->transport_link == NTB_LINK_UP) {
1271250079Scarl		callout_reset(&qp->link_work,
1272250079Scarl		    NTB_LINK_DOWN_TIMEOUT * hz / 1000, ntb_qp_link_work, qp);
1273250079Scarl	}
1274250079Scarl}
1275250079Scarl
1276250079Scarl/* Link down event*/
1277250079Scarlstatic void
1278250079Scarlntb_transport_link_cleanup(struct ntb_netdev *nt)
1279250079Scarl{
1280250079Scarl	int i;
1281250079Scarl
1282289273Scem	/* Pass along the info to any clients */
1283289273Scem	for (i = 0; i < nt->max_qps; i++)
1284289273Scem		if (!test_bit(i, &nt->qp_bitmap))
1285289273Scem			ntb_qp_link_down(&nt->qps[i]);
1286289273Scem
1287250079Scarl	if (nt->transport_link == NTB_LINK_DOWN)
1288250079Scarl		callout_drain(&nt->link_work);
1289250079Scarl	else
1290250079Scarl		nt->transport_link = NTB_LINK_DOWN;
1291250079Scarl
1292289341Scem	/*
1293250079Scarl	 * The scratchpad registers keep the values if the remote side
1294250079Scarl	 * goes down, blast them now to give them a sane value the next
1295250079Scarl	 * time they are accessed
1296250079Scarl	 */
1297250079Scarl	for (i = 0; i < IF_NTB_MAX_SPAD; i++)
1298250079Scarl		ntb_write_local_spad(nt->ntb, i, 0);
1299250079Scarl}
1300250079Scarl
1301250079Scarl
1302250079Scarlstatic void
1303250079Scarlntb_qp_link_down(struct ntb_transport_qp *qp)
1304250079Scarl{
1305250079Scarl
1306250079Scarl	ntb_qp_link_cleanup(qp);
1307250079Scarl}
1308250079Scarl
1309250079Scarlstatic void
1310250079Scarlntb_qp_link_cleanup(struct ntb_transport_qp *qp)
1311250079Scarl{
1312250079Scarl	struct ntb_netdev *nt = qp->transport;
1313250079Scarl
1314250079Scarl	if (qp->qp_link == NTB_LINK_DOWN) {
1315250079Scarl		callout_drain(&qp->link_work);
1316250079Scarl		return;
1317250079Scarl	}
1318250079Scarl
1319250079Scarl	if (qp->event_handler != NULL)
1320250079Scarl		qp->event_handler(qp->cb_data, NTB_LINK_DOWN);
1321250079Scarl
1322250079Scarl	qp->qp_link = NTB_LINK_DOWN;
1323250079Scarl
1324250079Scarl	if (nt->transport_link == NTB_LINK_UP)
1325250079Scarl		callout_reset(&qp->link_work,
1326250079Scarl		    NTB_LINK_DOWN_TIMEOUT * hz / 1000, ntb_qp_link_work, qp);
1327250079Scarl}
1328250079Scarl
1329250079Scarl/* Link commanded down */
1330250079Scarl/**
1331250079Scarl * ntb_transport_link_down - Notify NTB transport to no longer enqueue data
1332250079Scarl * @qp: NTB transport layer queue to be disabled
1333250079Scarl *
1334250079Scarl * Notify NTB transport layer of client's desire to no longer receive data on
1335250079Scarl * transport queue specified.  It is the client's responsibility to ensure all
1336289266Scem * entries on queue are purged or otherwise handled appropriately.
1337250079Scarl */
1338250079Scarlstatic void
1339250079Scarlntb_transport_link_down(struct ntb_transport_qp *qp)
1340250079Scarl{
1341250079Scarl	int rc, val;
1342250079Scarl
1343250079Scarl	if (qp == NULL)
1344250079Scarl		return;
1345250079Scarl
1346250079Scarl	qp->client_ready = NTB_LINK_DOWN;
1347250079Scarl
1348250079Scarl	rc = ntb_read_remote_spad(qp->ntb, IF_NTB_QP_LINKS, &val);
1349250079Scarl	if (rc != 0)
1350250079Scarl		return;
1351250079Scarl
1352250079Scarl	rc = ntb_write_remote_spad(qp->ntb, IF_NTB_QP_LINKS,
1353250079Scarl	   val & ~(1 << qp->qp_num));
1354250079Scarl
1355250079Scarl	if (qp->qp_link == NTB_LINK_UP)
1356250079Scarl		ntb_send_link_down(qp);
1357250079Scarl	else
1358250079Scarl		callout_drain(&qp->link_work);
1359250079Scarl
1360250079Scarl}
1361250079Scarl
1362250079Scarlstatic void
1363250079Scarlntb_send_link_down(struct ntb_transport_qp *qp)
1364250079Scarl{
1365250079Scarl	struct ntb_queue_entry *entry;
1366250079Scarl	int i, rc;
1367250079Scarl
1368250079Scarl	if (qp->qp_link == NTB_LINK_DOWN)
1369250079Scarl		return;
1370250079Scarl
1371250079Scarl	qp->qp_link = NTB_LINK_DOWN;
1372250079Scarl
1373250079Scarl	for (i = 0; i < NTB_LINK_DOWN_TIMEOUT; i++) {
1374250079Scarl		entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q);
1375250079Scarl		if (entry != NULL)
1376250079Scarl			break;
1377250079Scarl		pause("NTB Wait for link down", hz / 10);
1378250079Scarl	}
1379250079Scarl
1380250079Scarl	if (entry == NULL)
1381250079Scarl		return;
1382250079Scarl
1383250079Scarl	entry->cb_data = NULL;
1384250079Scarl	entry->buf = NULL;
1385250079Scarl	entry->len = 0;
1386250079Scarl	entry->flags = IF_NTB_LINK_DOWN_FLAG;
1387250079Scarl
1388250079Scarl	mtx_lock(&qp->transport->tx_lock);
1389250079Scarl	rc = ntb_process_tx(qp, entry);
1390250079Scarl	if (rc != 0)
1391250079Scarl		printf("ntb: Failed to send link down\n");
1392250079Scarl	mtx_unlock(&qp->transport->tx_lock);
1393250079Scarl}
1394250079Scarl
1395250079Scarl
1396250079Scarl/* List Management */
1397250079Scarl
1398250079Scarlstatic void
1399250079Scarlntb_list_add(struct mtx *lock, struct ntb_queue_entry *entry,
1400250079Scarl    struct ntb_queue_list *list)
1401250079Scarl{
1402250079Scarl
1403250079Scarl	mtx_lock_spin(lock);
1404250079Scarl	STAILQ_INSERT_TAIL(list, entry, entry);
1405250079Scarl	mtx_unlock_spin(lock);
1406250079Scarl}
1407250079Scarl
1408250079Scarlstatic struct ntb_queue_entry *
1409250079Scarlntb_list_rm(struct mtx *lock, struct ntb_queue_list *list)
1410250079Scarl{
1411250079Scarl	struct ntb_queue_entry *entry;
1412250079Scarl
1413250079Scarl	mtx_lock_spin(lock);
1414250079Scarl	if (STAILQ_EMPTY(list)) {
1415250079Scarl		entry = NULL;
1416250079Scarl		goto out;
1417250079Scarl	}
1418250079Scarl	entry = STAILQ_FIRST(list);
1419250079Scarl	STAILQ_REMOVE_HEAD(list, entry);
1420250079Scarlout:
1421250079Scarl	mtx_unlock_spin(lock);
1422250079Scarl
1423250079Scarl	return (entry);
1424250079Scarl}
1425250079Scarl
1426250079Scarl/* Helper functions */
1427250079Scarl/* TODO: This too should really be part of the kernel */
1428250079Scarl#define EUI48_MULTICAST			1 << 0
1429250079Scarl#define EUI48_LOCALLY_ADMINISTERED	1 << 1
1430250079Scarlstatic void
1431250079Scarlcreate_random_local_eui48(u_char *eaddr)
1432250079Scarl{
1433250079Scarl	static uint8_t counter = 0;
1434250079Scarl	uint32_t seed = ticks;
1435250079Scarl
1436250079Scarl	eaddr[0] = EUI48_LOCALLY_ADMINISTERED;
1437250079Scarl	memcpy(&eaddr[1], &seed, sizeof(uint32_t));
1438250079Scarl	eaddr[5] = counter++;
1439250079Scarl}
1440250079Scarl
1441250079Scarl/**
1442250079Scarl * ntb_transport_max_size - Query the max payload size of a qp
1443250079Scarl * @qp: NTB transport layer queue to be queried
1444250079Scarl *
1445250079Scarl * Query the maximum payload size permissible on the given qp
1446250079Scarl *
1447250079Scarl * RETURNS: the max payload size of a qp
1448250079Scarl */
1449250079Scarlstatic unsigned int
1450250079Scarlntb_transport_max_size(struct ntb_transport_qp *qp)
1451250079Scarl{
1452250079Scarl
1453250079Scarl	if (qp == NULL)
1454250079Scarl		return (0);
1455250079Scarl
1456250079Scarl	return (qp->tx_max_frame - sizeof(struct ntb_payload_header));
1457250079Scarl}
1458