ntb_transport.c revision 289154
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 289154 2015-10-11 20:59:02Z 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>
35250079Scarl#include <sys/lock.h>
36250079Scarl#include <sys/malloc.h>
37250079Scarl#include <sys/module.h>
38250079Scarl#include <sys/mutex.h>
39250079Scarl#include <sys/queue.h>
40250079Scarl#include <sys/socket.h>
41250079Scarl#include <sys/sockio.h>
42250079Scarl#include <sys/taskqueue.h>
43250079Scarl#include <net/if.h>
44250079Scarl#include <net/if_media.h>
45250079Scarl#include <net/if_types.h>
46250079Scarl#include <net/if_var.h>
47250079Scarl#include <net/bpf.h>
48250079Scarl#include <net/ethernet.h>
49250079Scarl#include <vm/vm.h>
50250079Scarl#include <vm/pmap.h>
51250079Scarl#include <machine/bus.h>
52250079Scarl#include <machine/cpufunc.h>
53250079Scarl#include <machine/pmap.h>
54250079Scarl
55250079Scarl#include "../ntb_hw/ntb_hw.h"
56250079Scarl
57250079Scarl/*
58250079Scarl * The Non-Transparent Bridge (NTB) is a device on some Intel processors that
59250079Scarl * allows you to connect two systems using a PCI-e link.
60250079Scarl *
61250079Scarl * This module contains a protocol for sending and receiving messages, and
62250079Scarl * exposes that protocol through a simulated ethernet device called ntb.
63250079Scarl *
64250079Scarl * NOTE: Much of the code in this module is shared with Linux. Any patches may
65250079Scarl * be picked up and redistributed in Linux with a dual GPL/BSD license.
66250079Scarl */
67250079Scarl
68250079Scarl/* TODO: These functions should really be part of the kernel */
69250079Scarl#define test_bit(pos, bitmap_addr)  (*(bitmap_addr) & 1UL << (pos))
70250079Scarl#define set_bit(pos, bitmap_addr)   *(bitmap_addr) |= 1UL << (pos)
71250079Scarl#define clear_bit(pos, bitmap_addr) *(bitmap_addr) &= ~(1UL << (pos))
72250079Scarl
73250079Scarl#define KTR_NTB KTR_SPARE3
74250079Scarl
75250079Scarl#define NTB_TRANSPORT_VERSION	3
76250079Scarl#define NTB_RX_MAX_PKTS		64
77250079Scarl#define	NTB_RXQ_SIZE		300
78250079Scarl
79250079Scarlstatic unsigned int transport_mtu = 0x4000 + ETHER_HDR_LEN + ETHER_CRC_LEN;
80250079Scarlstatic unsigned int max_num_clients = 1;
81250079Scarl
82250079ScarlSTAILQ_HEAD(ntb_queue_list, ntb_queue_entry);
83250079Scarl
84250079Scarlstruct ntb_queue_entry {
85250079Scarl	/* ntb_queue list reference */
86250079Scarl	STAILQ_ENTRY(ntb_queue_entry) entry;
87250079Scarl
88250079Scarl	/* info on data to be transfered */
89250079Scarl	void		*cb_data;
90250079Scarl	void		*buf;
91250079Scarl	uint64_t	len;
92250079Scarl	uint64_t	flags;
93250079Scarl};
94250079Scarl
95250079Scarlstruct ntb_rx_info {
96250079Scarl	unsigned int entry;
97250079Scarl};
98250079Scarl
99250079Scarlstruct ntb_transport_qp {
100250079Scarl	struct ntb_netdev	*transport;
101250079Scarl	struct ntb_softc	*ntb;
102250079Scarl
103250079Scarl	void			*cb_data;
104250079Scarl
105250079Scarl	bool			client_ready;
106250079Scarl	bool			qp_link;
107255281Scarl	uint8_t			qp_num;	/* Only 64 QPs are allowed.  0-63 */
108250079Scarl
109250079Scarl	struct ntb_rx_info	*rx_info;
110250079Scarl	struct ntb_rx_info	*remote_rx_info;
111250079Scarl
112250079Scarl	void (*tx_handler) (struct ntb_transport_qp *qp, void *qp_data,
113250079Scarl	    void *data, int len);
114250079Scarl	struct ntb_queue_list	tx_free_q;
115250079Scarl	struct mtx		ntb_tx_free_q_lock;
116250079Scarl	void			*tx_mw;
117250079Scarl	uint64_t		tx_index;
118250079Scarl	uint64_t		tx_max_entry;
119250079Scarl	uint64_t		tx_max_frame;
120250079Scarl
121250079Scarl	void (*rx_handler) (struct ntb_transport_qp *qp, void *qp_data,
122250079Scarl	    void *data, int len);
123250079Scarl	struct ntb_queue_list	rx_pend_q;
124250079Scarl	struct ntb_queue_list	rx_free_q;
125250079Scarl	struct mtx		ntb_rx_pend_q_lock;
126250079Scarl	struct mtx		ntb_rx_free_q_lock;
127250079Scarl	struct task		rx_completion_task;
128250079Scarl	void			*rx_buff;
129250079Scarl	uint64_t		rx_index;
130250079Scarl	uint64_t		rx_max_entry;
131250079Scarl	uint64_t		rx_max_frame;
132250079Scarl
133250079Scarl	void (*event_handler) (void *data, int status);
134250079Scarl	struct callout		link_work;
135250079Scarl	struct callout		queue_full;
136250079Scarl	struct callout		rx_full;
137250079Scarl
138250079Scarl	uint64_t		last_rx_no_buf;
139250079Scarl
140250079Scarl	/* Stats */
141250079Scarl	uint64_t		rx_bytes;
142250079Scarl	uint64_t		rx_pkts;
143250079Scarl	uint64_t		rx_ring_empty;
144250079Scarl	uint64_t		rx_err_no_buf;
145250079Scarl	uint64_t		rx_err_oflow;
146250079Scarl	uint64_t		rx_err_ver;
147250079Scarl	uint64_t		tx_bytes;
148250079Scarl	uint64_t		tx_pkts;
149250079Scarl	uint64_t		tx_ring_full;
150250079Scarl};
151250079Scarl
152250079Scarlstruct ntb_queue_handlers {
153250079Scarl	void (*rx_handler) (struct ntb_transport_qp *qp, void *qp_data,
154250079Scarl	    void *data, int len);
155250079Scarl	void (*tx_handler) (struct ntb_transport_qp *qp, void *qp_data,
156250079Scarl	    void *data, int len);
157250079Scarl	void (*event_handler) (void *data, int status);
158250079Scarl};
159250079Scarl
160250079Scarl
161250079Scarlstruct ntb_transport_mw {
162250079Scarl	size_t		size;
163250079Scarl	void		*virt_addr;
164250079Scarl	vm_paddr_t	dma_addr;
165250079Scarl};
166250079Scarl
167250079Scarlstruct ntb_netdev {
168250079Scarl	struct ntb_softc	*ntb;
169250079Scarl	struct ifnet		*ifp;
170250079Scarl	struct ntb_transport_mw	mw[NTB_NUM_MW];
171250079Scarl	struct ntb_transport_qp	*qps;
172250079Scarl	uint64_t		max_qps;
173250079Scarl	uint64_t		qp_bitmap;
174250079Scarl	bool			transport_link;
175250079Scarl	struct callout		link_work;
176250079Scarl	struct ntb_transport_qp *qp;
177250079Scarl	uint64_t		bufsize;
178250079Scarl	u_char			eaddr[ETHER_ADDR_LEN];
179250079Scarl	struct mtx		tx_lock;
180250079Scarl	struct mtx		rx_lock;
181250079Scarl};
182250079Scarl
183250079Scarlstatic struct ntb_netdev net_softc;
184250079Scarl
185250079Scarlenum {
186250079Scarl	IF_NTB_DESC_DONE_FLAG = 1 << 0,
187250079Scarl	IF_NTB_LINK_DOWN_FLAG = 1 << 1,
188250079Scarl};
189250079Scarl
190250079Scarlstruct ntb_payload_header {
191250079Scarl	uint64_t ver;
192250079Scarl	uint64_t len;
193250079Scarl	uint64_t flags;
194250079Scarl};
195250079Scarl
196250079Scarlenum {
197289153Scem	/*
198289153Scem	 * The order of this enum is part of the if_ntb remote protocol.  Do
199289153Scem	 * not reorder without bumping protocol version (and it's probably best
200289153Scem	 * to keep the protocol in lock-step with the Linux NTB driver.
201289153Scem	 */
202250079Scarl	IF_NTB_VERSION = 0,
203289153Scem	IF_NTB_QP_LINKS,
204250079Scarl	IF_NTB_NUM_QPS,
205289153Scem	IF_NTB_NUM_MWS,
206289153Scem	/*
207289153Scem	 * N.B.: transport_link_work assumes MW1 enums = MW0 + 2.
208289153Scem	 */
209289153Scem	IF_NTB_MW0_SZ_HIGH,
210289153Scem	IF_NTB_MW0_SZ_LOW,
211289153Scem	IF_NTB_MW1_SZ_HIGH,
212289153Scem	IF_NTB_MW1_SZ_LOW,
213250079Scarl	IF_NTB_MAX_SPAD,
214250079Scarl};
215250079Scarl
216250079Scarl#define QP_TO_MW(qp)		((qp) % NTB_NUM_MW)
217250079Scarl#define NTB_QP_DEF_NUM_ENTRIES	100
218250079Scarl#define NTB_LINK_DOWN_TIMEOUT	10
219250079Scarl
220250079Scarlstatic int ntb_handle_module_events(struct module *m, int what, void *arg);
221250079Scarlstatic int ntb_setup_interface(void);
222250079Scarlstatic int ntb_teardown_interface(void);
223250079Scarlstatic void ntb_net_init(void *arg);
224250079Scarlstatic int ntb_ioctl(struct ifnet *ifp, u_long command, caddr_t data);
225250079Scarlstatic void ntb_start(struct ifnet *ifp);
226250079Scarlstatic void ntb_net_tx_handler(struct ntb_transport_qp *qp, void *qp_data,
227250079Scarl    void *data, int len);
228250079Scarlstatic void ntb_net_rx_handler(struct ntb_transport_qp *qp, void *qp_data,
229250079Scarl    void *data, int len);
230250079Scarlstatic void ntb_net_event_handler(void *data, int status);
231250079Scarlstatic int ntb_transport_init(struct ntb_softc *ntb);
232250079Scarlstatic void ntb_transport_free(void *transport);
233250079Scarlstatic void ntb_transport_init_queue(struct ntb_netdev *nt,
234250079Scarl    unsigned int qp_num);
235250079Scarlstatic void ntb_transport_free_queue(struct ntb_transport_qp *qp);
236250079Scarlstatic struct ntb_transport_qp * ntb_transport_create_queue(void *data,
237250079Scarl    struct ntb_softc *pdev, const struct ntb_queue_handlers *handlers);
238250079Scarlstatic void ntb_transport_link_up(struct ntb_transport_qp *qp);
239250079Scarlstatic int ntb_transport_tx_enqueue(struct ntb_transport_qp *qp, void *cb,
240250079Scarl    void *data, unsigned int len);
241250079Scarlstatic int ntb_process_tx(struct ntb_transport_qp *qp,
242250079Scarl    struct ntb_queue_entry *entry);
243250079Scarlstatic void ntb_tx_copy_task(struct ntb_transport_qp *qp,
244250079Scarl    struct ntb_queue_entry *entry, void *offset);
245250079Scarlstatic void ntb_qp_full(void *arg);
246250079Scarlstatic void ntb_transport_rxc_db(void *data, int db_num);
247250079Scarlstatic void ntb_rx_pendq_full(void *arg);
248250079Scarlstatic void ntb_transport_rx(struct ntb_transport_qp *qp);
249250079Scarlstatic int ntb_process_rxc(struct ntb_transport_qp *qp);
250250079Scarlstatic void ntb_rx_copy_task(struct ntb_transport_qp *qp,
251250079Scarl    struct ntb_queue_entry *entry, void *offset);
252250079Scarlstatic void ntb_rx_completion_task(void *arg, int pending);
253250079Scarlstatic void ntb_transport_event_callback(void *data, enum ntb_hw_event event);
254250079Scarlstatic void ntb_transport_link_work(void *arg);
255250079Scarlstatic int ntb_set_mw(struct ntb_netdev *nt, int num_mw, unsigned int size);
256289153Scemstatic void ntb_free_mw(struct ntb_netdev *nt, int num_mw);
257250079Scarlstatic void ntb_transport_setup_qp_mw(struct ntb_netdev *nt,
258250079Scarl    unsigned int qp_num);
259250079Scarlstatic void ntb_qp_link_work(void *arg);
260250079Scarlstatic void ntb_transport_link_cleanup(struct ntb_netdev *nt);
261250079Scarlstatic void ntb_qp_link_down(struct ntb_transport_qp *qp);
262250079Scarlstatic void ntb_qp_link_cleanup(struct ntb_transport_qp *qp);
263250079Scarlstatic void ntb_transport_link_down(struct ntb_transport_qp *qp);
264250079Scarlstatic void ntb_send_link_down(struct ntb_transport_qp *qp);
265250079Scarlstatic void ntb_list_add(struct mtx *lock, struct ntb_queue_entry *entry,
266250079Scarl    struct ntb_queue_list *list);
267250079Scarlstatic struct ntb_queue_entry *ntb_list_rm(struct mtx *lock,
268250079Scarl    struct ntb_queue_list *list);
269250079Scarlstatic void create_random_local_eui48(u_char *eaddr);
270250079Scarlstatic unsigned int ntb_transport_max_size(struct ntb_transport_qp *qp);
271250079Scarl
272250079ScarlMALLOC_DEFINE(M_NTB_IF, "if_ntb", "ntb network driver");
273250079Scarl
274250079Scarl/* Module setup and teardown */
275250079Scarlstatic int
276250079Scarlntb_handle_module_events(struct module *m, int what, void *arg)
277250079Scarl{
278250079Scarl	int err = 0;
279250079Scarl
280250079Scarl	switch (what) {
281250079Scarl	case MOD_LOAD:
282250079Scarl		err = ntb_setup_interface();
283250079Scarl		break;
284250079Scarl	case MOD_UNLOAD:
285250079Scarl		err = ntb_teardown_interface();
286250079Scarl		break;
287250079Scarl	default:
288250079Scarl		err = EOPNOTSUPP;
289250079Scarl		break;
290250079Scarl	}
291250079Scarl	return (err);
292250079Scarl}
293250079Scarl
294255271Scarlstatic moduledata_t if_ntb_mod = {
295255271Scarl	"if_ntb",
296250079Scarl	ntb_handle_module_events,
297250079Scarl	NULL
298250079Scarl};
299250079Scarl
300255271ScarlDECLARE_MODULE(if_ntb, if_ntb_mod, SI_SUB_KLD, SI_ORDER_ANY);
301255271ScarlMODULE_DEPEND(if_ntb, ntb_hw, 1, 1, 1);
302250079Scarl
303250079Scarlstatic int
304250079Scarlntb_setup_interface()
305250079Scarl{
306250079Scarl	struct ifnet *ifp;
307250079Scarl	struct ntb_queue_handlers handlers = { ntb_net_rx_handler,
308250079Scarl	    ntb_net_tx_handler, ntb_net_event_handler };
309250079Scarl
310250079Scarl	net_softc.ntb = devclass_get_softc(devclass_find("ntb_hw"), 0);
311250079Scarl	if (net_softc.ntb == NULL) {
312255281Scarl		printf("ntb: Cannot find devclass\n");
313250079Scarl		return (ENXIO);
314250079Scarl	}
315250079Scarl
316250079Scarl	ntb_transport_init(net_softc.ntb);
317250079Scarl
318250079Scarl	ifp = net_softc.ifp = if_alloc(IFT_ETHER);
319250079Scarl	if (ifp == NULL) {
320250079Scarl		printf("ntb: cannot allocate ifnet structure\n");
321250079Scarl		return (ENOMEM);
322250079Scarl	}
323250079Scarl
324250079Scarl	net_softc.qp = ntb_transport_create_queue(ifp, net_softc.ntb,
325250079Scarl	    &handlers);
326250079Scarl	if_initname(ifp, "ntb", 0);
327250079Scarl	ifp->if_init = ntb_net_init;
328250079Scarl	ifp->if_softc = &net_softc;
329250079Scarl	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
330250079Scarl	ifp->if_ioctl = ntb_ioctl;
331250079Scarl	ifp->if_start = ntb_start;
332250079Scarl	IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
333250079Scarl	ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN;
334250079Scarl	IFQ_SET_READY(&ifp->if_snd);
335250079Scarl	create_random_local_eui48(net_softc.eaddr);
336250079Scarl	ether_ifattach(ifp, net_softc.eaddr);
337250079Scarl	ifp->if_capabilities = IFCAP_HWCSUM | IFCAP_JUMBO_MTU;
338250079Scarl	ifp->if_capenable = ifp->if_capabilities;
339250079Scarl
340250079Scarl	ntb_transport_link_up(net_softc.qp);
341250079Scarl	net_softc.bufsize = ntb_transport_max_size(net_softc.qp) +
342250079Scarl	    sizeof(struct ether_header);
343250079Scarl	return (0);
344250079Scarl}
345250079Scarl
346250079Scarlstatic int
347250079Scarlntb_teardown_interface()
348250079Scarl{
349250079Scarl
350255280Scarl	if (net_softc.qp != NULL)
351255280Scarl		ntb_transport_link_down(net_softc.qp);
352250079Scarl
353255280Scarl	if (net_softc.ifp != NULL) {
354255280Scarl		ether_ifdetach(net_softc.ifp);
355255280Scarl		if_free(net_softc.ifp);
356255280Scarl	}
357250079Scarl
358255280Scarl	if (net_softc.qp != NULL) {
359255280Scarl		ntb_transport_free_queue(net_softc.qp);
360255280Scarl		ntb_transport_free(&net_softc);
361255280Scarl	}
362255280Scarl
363250079Scarl	return (0);
364250079Scarl}
365250079Scarl
366250079Scarl/* Network device interface */
367250079Scarl
368250079Scarlstatic void
369250079Scarlntb_net_init(void *arg)
370250079Scarl{
371250079Scarl	struct ntb_netdev *ntb_softc = arg;
372250079Scarl	struct ifnet *ifp = ntb_softc->ifp;
373250079Scarl
374250079Scarl	ifp->if_drv_flags |= IFF_DRV_RUNNING;
375250079Scarl	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
376250079Scarl	ifp->if_flags |= IFF_UP;
377250079Scarl	if_link_state_change(ifp, LINK_STATE_UP);
378250079Scarl}
379250079Scarl
380250079Scarlstatic int
381250079Scarlntb_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
382250079Scarl{
383250079Scarl	struct ntb_netdev *nt = ifp->if_softc;
384250079Scarl	struct ifreq *ifr = (struct ifreq *)data;
385250079Scarl	int error = 0;
386250079Scarl
387250079Scarl	switch (command) {
388250079Scarl	case SIOCSIFMTU:
389250079Scarl	    {
390250079Scarl		if (ifr->ifr_mtu > ntb_transport_max_size(nt->qp) -
391250079Scarl		    ETHER_HDR_LEN - ETHER_CRC_LEN) {
392250079Scarl			error = EINVAL;
393250079Scarl			break;
394250079Scarl		}
395250079Scarl
396250079Scarl		ifp->if_mtu = ifr->ifr_mtu;
397250079Scarl		break;
398250079Scarl	    }
399250079Scarl	default:
400250079Scarl		error = ether_ioctl(ifp, command, data);
401250079Scarl		break;
402250079Scarl	}
403250079Scarl
404250079Scarl	return (error);
405250079Scarl}
406250079Scarl
407250079Scarl
408250079Scarlstatic void
409250079Scarlntb_start(struct ifnet *ifp)
410250079Scarl{
411250079Scarl	struct mbuf *m_head;
412250079Scarl	struct ntb_netdev *nt = ifp->if_softc;
413250079Scarl	int rc;
414250079Scarl
415250079Scarl	mtx_lock(&nt->tx_lock);
416250079Scarl	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
417250079Scarl	CTR0(KTR_NTB, "TX: ntb_start");
418250079Scarl	while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) {
419250079Scarl		IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
420250079Scarl		CTR1(KTR_NTB, "TX: start mbuf %p", m_head);
421250079Scarl		rc = ntb_transport_tx_enqueue(nt->qp, m_head, m_head,
422250079Scarl			     m_length(m_head, NULL));
423250079Scarl		if (rc != 0) {
424250079Scarl			CTR1(KTR_NTB,
425255281Scarl			    "TX: could not tx mbuf %p. Returning to snd q",
426250079Scarl			    m_head);
427250079Scarl			if (rc == EAGAIN) {
428250079Scarl				ifp->if_drv_flags |= IFF_DRV_OACTIVE;
429250079Scarl				IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
430250079Scarl				callout_reset(&nt->qp->queue_full, hz / 1000,
431250079Scarl				    ntb_qp_full, ifp);
432250079Scarl			}
433250079Scarl			break;
434250079Scarl		}
435250079Scarl
436250079Scarl	}
437250079Scarl	mtx_unlock(&nt->tx_lock);
438250079Scarl}
439250079Scarl
440250079Scarl/* Network Device Callbacks */
441250079Scarlstatic void
442250079Scarlntb_net_tx_handler(struct ntb_transport_qp *qp, void *qp_data, void *data,
443250079Scarl    int len)
444250079Scarl{
445250079Scarl
446250079Scarl	m_freem(data);
447250079Scarl	CTR1(KTR_NTB, "TX: tx_handler freeing mbuf %p", data);
448250079Scarl}
449250079Scarl
450250079Scarlstatic void
451250079Scarlntb_net_rx_handler(struct ntb_transport_qp *qp, void *qp_data, void *data,
452250079Scarl    int len)
453250079Scarl{
454250079Scarl	struct mbuf *m = data;
455250079Scarl	struct ifnet *ifp = qp_data;
456250079Scarl
457250079Scarl	CTR0(KTR_NTB, "RX: rx handler");
458250079Scarl	(*ifp->if_input)(ifp, m);
459250079Scarl}
460250079Scarl
461250079Scarlstatic void
462250079Scarlntb_net_event_handler(void *data, int status)
463250079Scarl{
464250079Scarl
465250079Scarl}
466250079Scarl
467250079Scarl/* Transport Init and teardown */
468250079Scarl
469250079Scarlstatic int
470250079Scarlntb_transport_init(struct ntb_softc *ntb)
471250079Scarl{
472250079Scarl	struct ntb_netdev *nt = &net_softc;
473250079Scarl	int rc, i;
474250079Scarl
475250079Scarl	nt->max_qps = max_num_clients;
476250079Scarl	ntb_register_transport(ntb, nt);
477250079Scarl	mtx_init(&nt->tx_lock, "ntb transport tx", NULL, MTX_DEF);
478250079Scarl	mtx_init(&nt->rx_lock, "ntb transport rx", NULL, MTX_DEF);
479250079Scarl
480250079Scarl	nt->qps = malloc(nt->max_qps * sizeof(struct ntb_transport_qp),
481250079Scarl			  M_NTB_IF, M_WAITOK|M_ZERO);
482250079Scarl
483250079Scarl	nt->qp_bitmap = ((uint64_t) 1 << nt->max_qps) - 1;
484250079Scarl
485250079Scarl	for (i = 0; i < nt->max_qps; i++)
486250079Scarl		ntb_transport_init_queue(nt, i);
487250079Scarl
488250079Scarl	callout_init(&nt->link_work, 0);
489250079Scarl
490250079Scarl	rc = ntb_register_event_callback(ntb,
491250079Scarl					 ntb_transport_event_callback);
492250079Scarl	if (rc != 0)
493250079Scarl		goto err;
494250079Scarl
495255268Scarl	if (ntb_query_link_status(ntb)) {
496255268Scarl		if (bootverbose)
497255268Scarl			device_printf(ntb_get_device(ntb), "link up\n");
498250079Scarl		callout_reset(&nt->link_work, 0, ntb_transport_link_work, nt);
499255268Scarl	}
500250079Scarl
501250079Scarl	return (0);
502250079Scarl
503250079Scarlerr:
504250079Scarl	free(nt->qps, M_NTB_IF);
505250079Scarl	ntb_unregister_transport(ntb);
506250079Scarl	return (rc);
507250079Scarl}
508250079Scarl
509250079Scarlstatic void
510250079Scarlntb_transport_free(void *transport)
511250079Scarl{
512250079Scarl	struct ntb_netdev *nt = transport;
513250079Scarl	struct ntb_softc *ntb = nt->ntb;
514250079Scarl	int i;
515250079Scarl
516250079Scarl	nt->transport_link = NTB_LINK_DOWN;
517250079Scarl
518250079Scarl	callout_drain(&nt->link_work);
519250079Scarl
520255281Scarl	/* verify that all the qps are freed */
521250079Scarl	for (i = 0; i < nt->max_qps; i++)
522250079Scarl		if (!test_bit(i, &nt->qp_bitmap))
523250079Scarl			ntb_transport_free_queue(&nt->qps[i]);
524250079Scarl
525250079Scarl
526250079Scarl	ntb_unregister_event_callback(ntb);
527250079Scarl
528250079Scarl	for (i = 0; i < NTB_NUM_MW; i++)
529289153Scem		ntb_free_mw(nt, i);
530250079Scarl
531250079Scarl	free(nt->qps, M_NTB_IF);
532250079Scarl	ntb_unregister_transport(ntb);
533250079Scarl}
534250079Scarl
535250079Scarlstatic void
536250079Scarlntb_transport_init_queue(struct ntb_netdev *nt, unsigned int qp_num)
537250079Scarl{
538250079Scarl	struct ntb_transport_qp *qp;
539250079Scarl	unsigned int num_qps_mw, tx_size;
540250079Scarl	uint8_t mw_num = QP_TO_MW(qp_num);
541250079Scarl
542250079Scarl	qp = &nt->qps[qp_num];
543250079Scarl	qp->qp_num = qp_num;
544250079Scarl	qp->transport = nt;
545250079Scarl	qp->ntb = nt->ntb;
546250079Scarl	qp->qp_link = NTB_LINK_DOWN;
547250079Scarl	qp->client_ready = NTB_LINK_DOWN;
548250079Scarl	qp->event_handler = NULL;
549250079Scarl
550250079Scarl	if (nt->max_qps % NTB_NUM_MW && mw_num < nt->max_qps % NTB_NUM_MW)
551250079Scarl		num_qps_mw = nt->max_qps / NTB_NUM_MW + 1;
552250079Scarl	else
553250079Scarl		num_qps_mw = nt->max_qps / NTB_NUM_MW;
554250079Scarl
555250079Scarl	tx_size = (unsigned int) ntb_get_mw_size(qp->ntb, mw_num) / num_qps_mw;
556250079Scarl	qp->rx_info = (struct ntb_rx_info *)
557250079Scarl	    ((char *)ntb_get_mw_vbase(qp->ntb, mw_num) +
558250079Scarl	    (qp_num / NTB_NUM_MW * tx_size));
559250079Scarl	tx_size -= sizeof(struct ntb_rx_info);
560250079Scarl
561289152Scem	qp->tx_mw = qp->rx_info + 1;
562250079Scarl	qp->tx_max_frame = min(transport_mtu + sizeof(struct ntb_payload_header),
563250079Scarl	    tx_size);
564250079Scarl	qp->tx_max_entry = tx_size / qp->tx_max_frame;
565250079Scarl	qp->tx_index = 0;
566250079Scarl
567250079Scarl	callout_init(&qp->link_work, 0);
568283291Sjkim	callout_init(&qp->queue_full, 1);
569283291Sjkim	callout_init(&qp->rx_full, 1);
570250079Scarl
571250079Scarl	mtx_init(&qp->ntb_rx_pend_q_lock, "ntb rx pend q", NULL, MTX_SPIN);
572250079Scarl	mtx_init(&qp->ntb_rx_free_q_lock, "ntb rx free q", NULL, MTX_SPIN);
573250079Scarl	mtx_init(&qp->ntb_tx_free_q_lock, "ntb tx free q", NULL, MTX_SPIN);
574250079Scarl	TASK_INIT(&qp->rx_completion_task, 0, ntb_rx_completion_task, qp);
575250079Scarl
576250079Scarl	STAILQ_INIT(&qp->rx_pend_q);
577250079Scarl	STAILQ_INIT(&qp->rx_free_q);
578250079Scarl	STAILQ_INIT(&qp->tx_free_q);
579250079Scarl}
580250079Scarl
581250079Scarlstatic void
582250079Scarlntb_transport_free_queue(struct ntb_transport_qp *qp)
583250079Scarl{
584250079Scarl	struct ntb_queue_entry *entry;
585250079Scarl
586250079Scarl	if (qp == NULL)
587250079Scarl		return;
588250079Scarl
589250079Scarl	callout_drain(&qp->link_work);
590250079Scarl
591250079Scarl	ntb_unregister_db_callback(qp->ntb, qp->qp_num);
592250079Scarl
593250079Scarl	while ((entry = ntb_list_rm(&qp->ntb_rx_free_q_lock, &qp->rx_free_q)))
594250079Scarl		free(entry, M_NTB_IF);
595250079Scarl
596250079Scarl	while ((entry = ntb_list_rm(&qp->ntb_rx_pend_q_lock, &qp->rx_pend_q)))
597250079Scarl		free(entry, M_NTB_IF);
598250079Scarl
599250079Scarl	while ((entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q)))
600250079Scarl		free(entry, M_NTB_IF);
601250079Scarl
602250079Scarl	set_bit(qp->qp_num, &qp->transport->qp_bitmap);
603250079Scarl}
604250079Scarl
605250079Scarl/**
606250079Scarl * ntb_transport_create_queue - Create a new NTB transport layer queue
607250079Scarl * @rx_handler: receive callback function
608250079Scarl * @tx_handler: transmit callback function
609250079Scarl * @event_handler: event callback function
610250079Scarl *
611250079Scarl * Create a new NTB transport layer queue and provide the queue with a callback
612250079Scarl * routine for both transmit and receive.  The receive callback routine will be
613250079Scarl * used to pass up data when the transport has received it on the queue.   The
614250079Scarl * transmit callback routine will be called when the transport has completed the
615250079Scarl * transmission of the data on the queue and the data is ready to be freed.
616250079Scarl *
617250079Scarl * RETURNS: pointer to newly created ntb_queue, NULL on error.
618250079Scarl */
619250079Scarlstatic struct ntb_transport_qp *
620250079Scarlntb_transport_create_queue(void *data, struct ntb_softc *pdev,
621250079Scarl    const struct ntb_queue_handlers *handlers)
622250079Scarl{
623250079Scarl	struct ntb_queue_entry *entry;
624250079Scarl	struct ntb_transport_qp *qp;
625250079Scarl	struct ntb_netdev *nt;
626250079Scarl	unsigned int free_queue;
627250079Scarl	int rc, i;
628250079Scarl
629250079Scarl	nt = ntb_find_transport(pdev);
630250079Scarl	if (nt == NULL)
631250079Scarl		goto err;
632250079Scarl
633250079Scarl	free_queue = ffs(nt->qp_bitmap);
634250079Scarl	if (free_queue == 0)
635250079Scarl		goto err;
636250079Scarl
637250079Scarl	/* decrement free_queue to make it zero based */
638250079Scarl	free_queue--;
639250079Scarl
640250079Scarl	clear_bit(free_queue, &nt->qp_bitmap);
641250079Scarl
642250079Scarl	qp = &nt->qps[free_queue];
643250079Scarl	qp->cb_data = data;
644250079Scarl	qp->rx_handler = handlers->rx_handler;
645250079Scarl	qp->tx_handler = handlers->tx_handler;
646250079Scarl	qp->event_handler = handlers->event_handler;
647250079Scarl
648250079Scarl	for (i = 0; i < NTB_QP_DEF_NUM_ENTRIES; i++) {
649250079Scarl		entry = malloc(sizeof(struct ntb_queue_entry), M_NTB_IF,
650250079Scarl		    M_WAITOK|M_ZERO);
651250079Scarl		entry->cb_data = nt->ifp;
652250079Scarl		entry->buf = NULL;
653250079Scarl		entry->len = transport_mtu;
654250079Scarl		ntb_list_add(&qp->ntb_rx_pend_q_lock, entry, &qp->rx_pend_q);
655250079Scarl	}
656250079Scarl
657250079Scarl	for (i = 0; i < NTB_QP_DEF_NUM_ENTRIES; i++) {
658250079Scarl		entry = malloc(sizeof(struct ntb_queue_entry), M_NTB_IF,
659250079Scarl		    M_WAITOK|M_ZERO);
660250079Scarl		ntb_list_add(&qp->ntb_tx_free_q_lock, entry, &qp->tx_free_q);
661250079Scarl	}
662250079Scarl
663250079Scarl	rc = ntb_register_db_callback(qp->ntb, free_queue, qp,
664250079Scarl				      ntb_transport_rxc_db);
665250079Scarl	if (rc != 0)
666250079Scarl		goto err1;
667250079Scarl
668250079Scarl	return (qp);
669250079Scarl
670250079Scarlerr1:
671250079Scarl	while ((entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q)))
672250079Scarl		free(entry, M_NTB_IF);
673250079Scarl	while ((entry = ntb_list_rm(&qp->ntb_rx_free_q_lock, &qp->rx_free_q)))
674250079Scarl		free(entry, M_NTB_IF);
675250079Scarl	set_bit(free_queue, &nt->qp_bitmap);
676250079Scarlerr:
677250079Scarl	return (NULL);
678250079Scarl}
679250079Scarl
680250079Scarl/**
681250079Scarl * ntb_transport_link_up - Notify NTB transport of client readiness to use queue
682250079Scarl * @qp: NTB transport layer queue to be enabled
683250079Scarl *
684250079Scarl * Notify NTB transport layer of client readiness to use queue
685250079Scarl */
686250079Scarlstatic void
687250079Scarlntb_transport_link_up(struct ntb_transport_qp *qp)
688250079Scarl{
689250079Scarl
690250079Scarl	if (qp == NULL)
691250079Scarl		return;
692250079Scarl
693250079Scarl	qp->client_ready = NTB_LINK_UP;
694255268Scarl	if (bootverbose)
695255268Scarl		device_printf(ntb_get_device(qp->ntb), "qp client ready\n");
696250079Scarl
697250079Scarl	if (qp->transport->transport_link == NTB_LINK_UP)
698250079Scarl		callout_reset(&qp->link_work, 0, ntb_qp_link_work, qp);
699250079Scarl}
700250079Scarl
701250079Scarl
702250079Scarl
703250079Scarl/* Transport Tx */
704250079Scarl
705250079Scarl/**
706250079Scarl * ntb_transport_tx_enqueue - Enqueue a new NTB queue entry
707250079Scarl * @qp: NTB transport layer queue the entry is to be enqueued on
708250079Scarl * @cb: per buffer pointer for callback function to use
709250079Scarl * @data: pointer to data buffer that will be sent
710250079Scarl * @len: length of the data buffer
711250079Scarl *
712250079Scarl * Enqueue a new transmit buffer onto the transport queue from which a NTB
713250079Scarl * payload will be transmitted.  This assumes that a lock is behing held to
714250079Scarl * serialize access to the qp.
715250079Scarl *
716250079Scarl * RETURNS: An appropriate ERRNO error value on error, or zero for success.
717250079Scarl */
718250079Scarlstatic int
719250079Scarlntb_transport_tx_enqueue(struct ntb_transport_qp *qp, void *cb, void *data,
720250079Scarl    unsigned int len)
721250079Scarl{
722250079Scarl	struct ntb_queue_entry *entry;
723250079Scarl	int rc;
724250079Scarl
725250079Scarl	if (qp == NULL || qp->qp_link != NTB_LINK_UP || len == 0) {
726250079Scarl		CTR0(KTR_NTB, "TX: link not up");
727250079Scarl		return (EINVAL);
728250079Scarl	}
729250079Scarl
730250079Scarl	entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q);
731250079Scarl	if (entry == NULL) {
732255281Scarl		CTR0(KTR_NTB, "TX: could not get entry from tx_free_q");
733250079Scarl		return (ENOMEM);
734250079Scarl	}
735250079Scarl	CTR1(KTR_NTB, "TX: got entry %p from tx_free_q", entry);
736250079Scarl
737250079Scarl	entry->cb_data = cb;
738250079Scarl	entry->buf = data;
739250079Scarl	entry->len = len;
740250079Scarl	entry->flags = 0;
741250079Scarl
742250079Scarl	rc = ntb_process_tx(qp, entry);
743250079Scarl	if (rc != 0) {
744250079Scarl		ntb_list_add(&qp->ntb_tx_free_q_lock, entry, &qp->tx_free_q);
745250079Scarl		CTR1(KTR_NTB,
746250079Scarl		    "TX: process_tx failed. Returning entry %p to tx_free_q",
747250079Scarl		    entry);
748250079Scarl	}
749250079Scarl	return (rc);
750250079Scarl}
751250079Scarl
752250079Scarlstatic int
753250079Scarlntb_process_tx(struct ntb_transport_qp *qp, struct ntb_queue_entry *entry)
754250079Scarl{
755250079Scarl	void *offset;
756250079Scarl
757250079Scarl	offset = (char *)qp->tx_mw + qp->tx_max_frame * qp->tx_index;
758250079Scarl	CTR3(KTR_NTB,
759250079Scarl	    "TX: process_tx: tx_pkts=%u, tx_index=%u, remote entry=%u",
760250079Scarl	    qp->tx_pkts, qp->tx_index, qp->remote_rx_info->entry);
761250079Scarl	if (qp->tx_index == qp->remote_rx_info->entry) {
762250079Scarl		CTR0(KTR_NTB, "TX: ring full");
763250079Scarl		qp->tx_ring_full++;
764250079Scarl		return (EAGAIN);
765250079Scarl	}
766250079Scarl
767250079Scarl	if (entry->len > qp->tx_max_frame - sizeof(struct ntb_payload_header)) {
768250079Scarl		if (qp->tx_handler != NULL)
769250079Scarl			qp->tx_handler(qp, qp->cb_data, entry->buf,
770250079Scarl				       EIO);
771250079Scarl
772250079Scarl		ntb_list_add(&qp->ntb_tx_free_q_lock, entry, &qp->tx_free_q);
773250079Scarl		CTR1(KTR_NTB,
774250079Scarl		    "TX: frame too big. returning entry %p to tx_free_q",
775250079Scarl		    entry);
776250079Scarl		return (0);
777250079Scarl	}
778250079Scarl	CTR2(KTR_NTB, "TX: copying entry %p to offset %p", entry, offset);
779250079Scarl	ntb_tx_copy_task(qp, entry, offset);
780250079Scarl
781250079Scarl	qp->tx_index++;
782250079Scarl	qp->tx_index %= qp->tx_max_entry;
783250079Scarl
784250079Scarl	qp->tx_pkts++;
785250079Scarl
786250079Scarl	return (0);
787250079Scarl}
788250079Scarl
789250079Scarlstatic void
790250079Scarlntb_tx_copy_task(struct ntb_transport_qp *qp, struct ntb_queue_entry *entry,
791250079Scarl    void *offset)
792250079Scarl{
793250079Scarl	struct ntb_payload_header *hdr;
794250079Scarl
795250079Scarl	CTR2(KTR_NTB, "TX: copying %d bytes to offset %p", entry->len, offset);
796250079Scarl	if (entry->buf != NULL)
797250079Scarl		m_copydata((struct mbuf *)entry->buf, 0, entry->len, offset);
798250079Scarl
799250079Scarl	hdr = (struct ntb_payload_header *)((char *)offset + qp->tx_max_frame -
800250079Scarl	    sizeof(struct ntb_payload_header));
801250079Scarl	hdr->len = entry->len; /* TODO: replace with bus_space_write */
802250079Scarl	hdr->ver = qp->tx_pkts; /* TODO: replace with bus_space_write */
803250079Scarl	wmb();
804250079Scarl	/* TODO: replace with bus_space_write */
805250079Scarl	hdr->flags = entry->flags | IF_NTB_DESC_DONE_FLAG;
806250079Scarl
807250079Scarl	ntb_ring_sdb(qp->ntb, qp->qp_num);
808250079Scarl
809250079Scarl	/*
810250079Scarl	 * The entry length can only be zero if the packet is intended to be a
811250079Scarl	 * "link down" or similar.  Since no payload is being sent in these
812250079Scarl	 * cases, there is nothing to add to the completion queue.
813250079Scarl	 */
814250079Scarl	if (entry->len > 0) {
815250079Scarl		qp->tx_bytes += entry->len;
816250079Scarl
817250079Scarl		if (qp->tx_handler)
818250079Scarl			qp->tx_handler(qp, qp->cb_data, entry->cb_data,
819250079Scarl				       entry->len);
820250079Scarl	}
821250079Scarl
822250079Scarl	CTR2(KTR_NTB,
823250079Scarl	    "TX: entry %p sent. hdr->ver = %d, Returning to tx_free_q", entry,
824250079Scarl	    hdr->ver);
825250079Scarl	ntb_list_add(&qp->ntb_tx_free_q_lock, entry, &qp->tx_free_q);
826250079Scarl}
827250079Scarl
828250079Scarlstatic void
829250079Scarlntb_qp_full(void *arg)
830250079Scarl{
831250079Scarl
832250079Scarl	CTR0(KTR_NTB, "TX: qp_full callout");
833250079Scarl	ntb_start(arg);
834250079Scarl}
835250079Scarl
836250079Scarl/* Transport Rx */
837250079Scarlstatic void
838250079Scarlntb_transport_rxc_db(void *data, int db_num)
839250079Scarl{
840250079Scarl	struct ntb_transport_qp *qp = data;
841250079Scarl
842250079Scarl	ntb_transport_rx(qp);
843250079Scarl}
844250079Scarl
845250079Scarlstatic void
846250079Scarlntb_rx_pendq_full(void *arg)
847250079Scarl{
848250079Scarl
849250079Scarl	CTR0(KTR_NTB, "RX: ntb_rx_pendq_full callout");
850250079Scarl	ntb_transport_rx(arg);
851250079Scarl}
852250079Scarl
853250079Scarlstatic void
854250079Scarlntb_transport_rx(struct ntb_transport_qp *qp)
855250079Scarl{
856250079Scarl	int rc, i;
857250079Scarl
858250079Scarl	/*
859250079Scarl	 * Limit the number of packets processed in a single interrupt to
860250079Scarl	 * provide fairness to others
861250079Scarl	 */
862250079Scarl	mtx_lock(&qp->transport->rx_lock);
863250079Scarl	CTR0(KTR_NTB, "RX: transport_rx");
864250079Scarl	for (i = 0; i < NTB_RX_MAX_PKTS; i++) {
865250079Scarl		rc = ntb_process_rxc(qp);
866250079Scarl		if (rc != 0) {
867250079Scarl			CTR0(KTR_NTB, "RX: process_rxc failed");
868250079Scarl			break;
869250079Scarl		}
870250079Scarl	}
871250079Scarl	mtx_unlock(&qp->transport->rx_lock);
872250079Scarl}
873250079Scarl
874250079Scarlstatic int
875250079Scarlntb_process_rxc(struct ntb_transport_qp *qp)
876250079Scarl{
877250079Scarl	struct ntb_payload_header *hdr;
878250079Scarl	struct ntb_queue_entry *entry;
879250079Scarl	void *offset;
880250079Scarl
881250079Scarl	offset = (void *)
882250079Scarl	    ((char *)qp->rx_buff + qp->rx_max_frame * qp->rx_index);
883250079Scarl	hdr = (void *)
884250079Scarl	    ((char *)offset + qp->rx_max_frame -
885250079Scarl		sizeof(struct ntb_payload_header));
886250079Scarl
887250079Scarl	CTR1(KTR_NTB, "RX: process_rxc rx_index = %u", qp->rx_index);
888250079Scarl	entry = ntb_list_rm(&qp->ntb_rx_pend_q_lock, &qp->rx_pend_q);
889250079Scarl	if (entry == NULL) {
890250079Scarl		qp->rx_err_no_buf++;
891250079Scarl		CTR0(KTR_NTB, "RX: No entries in rx_pend_q");
892250079Scarl		return (ENOMEM);
893250079Scarl	}
894250079Scarl	callout_stop(&qp->rx_full);
895250079Scarl	CTR1(KTR_NTB, "RX: rx entry %p from rx_pend_q", entry);
896250079Scarl
897250079Scarl	if ((hdr->flags & IF_NTB_DESC_DONE_FLAG) == 0) {
898250079Scarl		CTR1(KTR_NTB,
899250079Scarl		    "RX: hdr not done. Returning entry %p to rx_pend_q", entry);
900250079Scarl		ntb_list_add(&qp->ntb_rx_pend_q_lock, entry, &qp->rx_pend_q);
901250079Scarl		qp->rx_ring_empty++;
902250079Scarl		return (EAGAIN);
903250079Scarl	}
904250079Scarl
905250079Scarl	if (hdr->ver != (uint32_t) qp->rx_pkts) {
906250079Scarl		CTR3(KTR_NTB,"RX: ver != rx_pkts (%x != %lx). "
907250079Scarl		    "Returning entry %p to rx_pend_q", hdr->ver, qp->rx_pkts,
908250079Scarl		    entry);
909250079Scarl		ntb_list_add(&qp->ntb_rx_pend_q_lock, entry, &qp->rx_pend_q);
910250079Scarl		qp->rx_err_ver++;
911250079Scarl		return (EIO);
912250079Scarl	}
913250079Scarl
914250079Scarl	if ((hdr->flags & IF_NTB_LINK_DOWN_FLAG) != 0) {
915250079Scarl		ntb_qp_link_down(qp);
916250079Scarl		CTR1(KTR_NTB,
917250079Scarl		    "RX: link down. adding entry %p back to rx_pend_q", entry);
918250079Scarl		ntb_list_add(&qp->ntb_rx_pend_q_lock, entry, &qp->rx_pend_q);
919250079Scarl		goto out;
920250079Scarl	}
921250079Scarl
922250079Scarl	if (hdr->len <= entry->len) {
923250079Scarl		entry->len = hdr->len;
924250079Scarl		ntb_rx_copy_task(qp, entry, offset);
925250079Scarl	} else {
926250079Scarl		CTR1(KTR_NTB,
927250079Scarl		    "RX: len too long. Returning entry %p to rx_pend_q", entry);
928250079Scarl		ntb_list_add(&qp->ntb_rx_pend_q_lock, entry, &qp->rx_pend_q);
929250079Scarl
930250079Scarl		qp->rx_err_oflow++;
931250079Scarl	}
932250079Scarl
933250079Scarl	qp->rx_bytes += hdr->len;
934250079Scarl	qp->rx_pkts++;
935250079Scarl	CTR1(KTR_NTB, "RX: received %ld rx_pkts", qp->rx_pkts);
936250079Scarl
937250079Scarl
938250079Scarlout:
939250079Scarl	/* Ensure that the data is globally visible before clearing the flag */
940250079Scarl	wmb();
941250079Scarl	hdr->flags = 0;
942250079Scarl	/* TODO: replace with bus_space_write */
943250079Scarl	qp->rx_info->entry = qp->rx_index;
944250079Scarl
945250079Scarl	qp->rx_index++;
946250079Scarl	qp->rx_index %= qp->rx_max_entry;
947250079Scarl
948250079Scarl	return (0);
949250079Scarl}
950250079Scarl
951250079Scarlstatic void
952250079Scarlntb_rx_copy_task(struct ntb_transport_qp *qp, struct ntb_queue_entry *entry,
953250079Scarl    void *offset)
954250079Scarl{
955250079Scarl	struct ifnet *ifp = entry->cb_data;
956250079Scarl	unsigned int len = entry->len;
957250079Scarl	struct mbuf *m;
958250079Scarl
959250079Scarl	CTR2(KTR_NTB, "RX: copying %d bytes from offset %p", len, offset);
960250079Scarl	m = m_devget(offset, len, 0, ifp, NULL);
961250079Scarl	m->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID;
962250079Scarl
963250079Scarl	entry->buf = (void *)m;
964250079Scarl
965250079Scarl	CTR2(KTR_NTB,
966250079Scarl	    "RX: copied entry %p to mbuf %p. Adding entry to rx_free_q", entry,
967250079Scarl	    m);
968250079Scarl	ntb_list_add(&qp->ntb_rx_free_q_lock, entry, &qp->rx_free_q);
969250079Scarl
970250079Scarl	taskqueue_enqueue(taskqueue_swi, &qp->rx_completion_task);
971250079Scarl}
972250079Scarl
973250079Scarlstatic void
974250079Scarlntb_rx_completion_task(void *arg, int pending)
975250079Scarl{
976250079Scarl	struct ntb_transport_qp *qp = arg;
977250079Scarl	struct mbuf *m;
978250079Scarl	struct ntb_queue_entry *entry;
979250079Scarl
980250079Scarl	CTR0(KTR_NTB, "RX: rx_completion_task");
981250079Scarl
982250079Scarl	while ((entry = ntb_list_rm(&qp->ntb_rx_free_q_lock, &qp->rx_free_q))) {
983250079Scarl		m = entry->buf;
984250079Scarl		CTR2(KTR_NTB, "RX: completing entry %p, mbuf %p", entry, m);
985250079Scarl		if (qp->rx_handler && qp->client_ready == NTB_LINK_UP)
986250079Scarl			qp->rx_handler(qp, qp->cb_data, m, entry->len);
987250079Scarl
988250079Scarl		entry->buf = NULL;
989250079Scarl		entry->len = qp->transport->bufsize;
990250079Scarl
991250079Scarl		CTR1(KTR_NTB,"RX: entry %p removed from rx_free_q "
992250079Scarl		    "and added to rx_pend_q", entry);
993250079Scarl		ntb_list_add(&qp->ntb_rx_pend_q_lock, entry, &qp->rx_pend_q);
994250079Scarl		if (qp->rx_err_no_buf > qp->last_rx_no_buf) {
995250079Scarl			qp->last_rx_no_buf = qp->rx_err_no_buf;
996250079Scarl			CTR0(KTR_NTB, "RX: could spawn rx task");
997250079Scarl			callout_reset(&qp->rx_full, hz / 1000, ntb_rx_pendq_full,
998250079Scarl			    qp);
999250079Scarl		}
1000250079Scarl	}
1001250079Scarl}
1002250079Scarl
1003250079Scarl/* Link Event handler */
1004250079Scarlstatic void
1005250079Scarlntb_transport_event_callback(void *data, enum ntb_hw_event event)
1006250079Scarl{
1007250079Scarl	struct ntb_netdev *nt = data;
1008250079Scarl
1009250079Scarl	switch (event) {
1010250079Scarl	case NTB_EVENT_HW_LINK_UP:
1011255268Scarl		if (bootverbose)
1012255268Scarl			device_printf(ntb_get_device(nt->ntb), "HW link up\n");
1013250079Scarl		callout_reset(&nt->link_work, 0, ntb_transport_link_work, nt);
1014250079Scarl		break;
1015250079Scarl	case NTB_EVENT_HW_LINK_DOWN:
1016255268Scarl		if (bootverbose)
1017255268Scarl			device_printf(ntb_get_device(nt->ntb), "HW link down\n");
1018250079Scarl		ntb_transport_link_cleanup(nt);
1019250079Scarl		break;
1020250079Scarl	default:
1021250079Scarl		panic("ntb: Unknown NTB event");
1022250079Scarl	}
1023250079Scarl}
1024250079Scarl
1025250079Scarl/* Link bring up */
1026250079Scarlstatic void
1027250079Scarlntb_transport_link_work(void *arg)
1028250079Scarl{
1029250079Scarl	struct ntb_netdev *nt = arg;
1030250079Scarl	struct ntb_softc *ntb = nt->ntb;
1031250079Scarl	struct ntb_transport_qp *qp;
1032289153Scem	uint64_t val64;
1033250079Scarl	uint32_t val;
1034250079Scarl	int rc, i;
1035250079Scarl
1036289153Scem	/* send the local info, in the opposite order of the way we read it */
1037289153Scem	for (i = 0; i < NTB_NUM_MW; i++) {
1038289153Scem		rc = ntb_write_remote_spad(ntb, IF_NTB_MW0_SZ_HIGH + (i * 2),
1039289153Scem		    ntb_get_mw_size(ntb, i) >> 32);
1040289153Scem		if (rc != 0)
1041289153Scem			goto out;
1042250079Scarl
1043289153Scem		rc = ntb_write_remote_spad(ntb, IF_NTB_MW0_SZ_LOW + (i * 2),
1044289153Scem		    (uint32_t)ntb_get_mw_size(ntb, i));
1045289153Scem		if (rc != 0)
1046289153Scem			goto out;
1047289153Scem	}
1048250079Scarl
1049289153Scem	rc = ntb_write_remote_spad(ntb, IF_NTB_NUM_MWS, NTB_NUM_MW);
1050250079Scarl	if (rc != 0)
1051250079Scarl		goto out;
1052250079Scarl
1053250079Scarl	rc = ntb_write_remote_spad(ntb, IF_NTB_NUM_QPS, nt->max_qps);
1054250079Scarl	if (rc != 0)
1055250079Scarl		goto out;
1056250079Scarl
1057289153Scem	rc = ntb_write_remote_spad(ntb, IF_NTB_VERSION, NTB_TRANSPORT_VERSION);
1058250079Scarl	if (rc != 0)
1059250079Scarl		goto out;
1060250079Scarl
1061250079Scarl	/* Query the remote side for its info */
1062250079Scarl	rc = ntb_read_local_spad(ntb, IF_NTB_VERSION, &val);
1063250079Scarl	if (rc != 0)
1064250079Scarl		goto out;
1065250079Scarl
1066250079Scarl	if (val != NTB_TRANSPORT_VERSION)
1067250079Scarl		goto out;
1068250079Scarl
1069250079Scarl	rc = ntb_read_local_spad(ntb, IF_NTB_NUM_QPS, &val);
1070250079Scarl	if (rc != 0)
1071250079Scarl		goto out;
1072250079Scarl
1073250079Scarl	if (val != nt->max_qps)
1074250079Scarl		goto out;
1075250079Scarl
1076289153Scem	rc = ntb_read_local_spad(ntb, IF_NTB_NUM_MWS, &val);
1077250079Scarl	if (rc != 0)
1078250079Scarl		goto out;
1079250079Scarl
1080289153Scem	if (val != NTB_NUM_MW)
1081250079Scarl		goto out;
1082250079Scarl
1083289153Scem	for (i = 0; i < NTB_NUM_MW; i++) {
1084289153Scem		rc = ntb_read_local_spad(ntb, IF_NTB_MW0_SZ_HIGH + (i * 2),
1085289153Scem		    &val);
1086289153Scem		if (rc != 0)
1087289153Scem			goto free_mws;
1088250079Scarl
1089289153Scem		val64 = (uint64_t)val << 32;
1090250079Scarl
1091289153Scem		rc = ntb_read_local_spad(ntb, IF_NTB_MW0_SZ_LOW + (i * 2),
1092289153Scem		    &val);
1093289153Scem		if (rc != 0)
1094289153Scem			goto free_mws;
1095250079Scarl
1096289153Scem		val64 |= val;
1097250079Scarl
1098289153Scem		rc = ntb_set_mw(nt, i, val64);
1099289153Scem		if (rc != 0)
1100289153Scem			goto free_mws;
1101289153Scem	}
1102289153Scem
1103250079Scarl	nt->transport_link = NTB_LINK_UP;
1104255268Scarl	if (bootverbose)
1105255268Scarl		device_printf(ntb_get_device(ntb), "transport link up\n");
1106250079Scarl
1107250079Scarl	for (i = 0; i < nt->max_qps; i++) {
1108250079Scarl		qp = &nt->qps[i];
1109250079Scarl
1110250079Scarl		ntb_transport_setup_qp_mw(nt, i);
1111250079Scarl
1112250079Scarl		if (qp->client_ready == NTB_LINK_UP)
1113250079Scarl			callout_reset(&qp->link_work, 0, ntb_qp_link_work, qp);
1114250079Scarl	}
1115250079Scarl
1116250079Scarl	return;
1117250079Scarl
1118289153Scemfree_mws:
1119289153Scem	for (i = 0; i < NTB_NUM_MW; i++)
1120289153Scem		ntb_free_mw(nt, i);
1121250079Scarlout:
1122250079Scarl	if (ntb_query_link_status(ntb))
1123250079Scarl		callout_reset(&nt->link_work,
1124289153Scem		    NTB_LINK_DOWN_TIMEOUT * hz / 1000, ntb_transport_link_work, nt);
1125250079Scarl}
1126250079Scarl
1127250079Scarlstatic int
1128250079Scarlntb_set_mw(struct ntb_netdev *nt, int num_mw, unsigned int size)
1129250079Scarl{
1130250079Scarl	struct ntb_transport_mw *mw = &nt->mw[num_mw];
1131250079Scarl
1132289154Scem	/* No need to re-setup */
1133289154Scem	if (mw->size == size)
1134289154Scem		return (0);
1135289154Scem
1136289154Scem	if (mw->size != 0)
1137289154Scem		ntb_free_mw(nt, num_mw);
1138289154Scem
1139250079Scarl	/* Alloc memory for receiving data.  Must be 4k aligned */
1140250079Scarl	mw->size = size;
1141250079Scarl
1142250079Scarl	mw->virt_addr = contigmalloc(mw->size, M_NTB_IF, M_ZERO, 0,
1143250079Scarl	    BUS_SPACE_MAXADDR, mw->size, 0);
1144250079Scarl	if (mw->virt_addr == NULL) {
1145289154Scem		mw->size = 0;
1146250079Scarl		printf("ntb: Unable to allocate MW buffer of size %d\n",
1147250079Scarl		    (int)mw->size);
1148250079Scarl		return (ENOMEM);
1149250079Scarl	}
1150250079Scarl	/* TODO: replace with bus_space_* functions */
1151250079Scarl	mw->dma_addr = vtophys(mw->virt_addr);
1152250079Scarl
1153250079Scarl	/* Notify HW the memory location of the receive buffer */
1154250079Scarl	ntb_set_mw_addr(nt->ntb, num_mw, mw->dma_addr);
1155250079Scarl
1156250079Scarl	return (0);
1157250079Scarl}
1158250079Scarl
1159250079Scarlstatic void
1160289153Scemntb_free_mw(struct ntb_netdev *nt, int num_mw)
1161289153Scem{
1162289153Scem	struct ntb_transport_mw *mw = &nt->mw[num_mw];
1163289153Scem
1164289153Scem	if (mw->virt_addr == NULL)
1165289153Scem		return;
1166289153Scem
1167289153Scem	contigfree(mw->virt_addr, mw->size, M_NTB_IF);
1168289153Scem	mw->virt_addr = NULL;
1169289153Scem}
1170289153Scem
1171289153Scemstatic void
1172250079Scarlntb_transport_setup_qp_mw(struct ntb_netdev *nt, unsigned int qp_num)
1173250079Scarl{
1174250079Scarl	struct ntb_transport_qp *qp = &nt->qps[qp_num];
1175250079Scarl	void *offset;
1176250079Scarl	unsigned int rx_size, num_qps_mw;
1177250079Scarl	uint8_t mw_num = QP_TO_MW(qp_num);
1178250079Scarl	unsigned int i;
1179250079Scarl
1180250079Scarl	if (nt->max_qps % NTB_NUM_MW && mw_num < nt->max_qps % NTB_NUM_MW)
1181250079Scarl		num_qps_mw = nt->max_qps / NTB_NUM_MW + 1;
1182250079Scarl	else
1183250079Scarl		num_qps_mw = nt->max_qps / NTB_NUM_MW;
1184250079Scarl
1185250079Scarl	rx_size = (unsigned int) nt->mw[mw_num].size / num_qps_mw;
1186250079Scarl	qp->remote_rx_info = (void *)((uint8_t *)nt->mw[mw_num].virt_addr +
1187250079Scarl			     (qp_num / NTB_NUM_MW * rx_size));
1188250079Scarl	rx_size -= sizeof(struct ntb_rx_info);
1189250079Scarl
1190289152Scem	qp->rx_buff = qp->remote_rx_info + 1;
1191250079Scarl	qp->rx_max_frame = min(transport_mtu + sizeof(struct ntb_payload_header),
1192250079Scarl	    rx_size);
1193250079Scarl	qp->rx_max_entry = rx_size / qp->rx_max_frame;
1194250079Scarl	qp->rx_index = 0;
1195250079Scarl	qp->tx_index = 0;
1196250079Scarl
1197250079Scarl	qp->remote_rx_info->entry = qp->rx_max_entry;
1198250079Scarl
1199250079Scarl	/* setup the hdr offsets with 0's */
1200250079Scarl	for (i = 0; i < qp->rx_max_entry; i++) {
1201250079Scarl		offset = (void *)((uint8_t *)qp->rx_buff +
1202250079Scarl		    qp->rx_max_frame * (i + 1) -
1203250079Scarl		    sizeof(struct ntb_payload_header));
1204250079Scarl		memset(offset, 0, sizeof(struct ntb_payload_header));
1205250079Scarl	}
1206250079Scarl
1207250079Scarl	qp->rx_pkts = 0;
1208250079Scarl	qp->tx_pkts = 0;
1209250079Scarl}
1210250079Scarl
1211250079Scarlstatic void
1212250079Scarlntb_qp_link_work(void *arg)
1213250079Scarl{
1214250079Scarl	struct ntb_transport_qp *qp = arg;
1215250079Scarl	struct ntb_softc *ntb = qp->ntb;
1216250079Scarl	struct ntb_netdev *nt = qp->transport;
1217250079Scarl	int rc, val;
1218250079Scarl
1219250079Scarl
1220250079Scarl	rc = ntb_read_remote_spad(ntb, IF_NTB_QP_LINKS, &val);
1221250079Scarl	if (rc != 0)
1222250079Scarl		return;
1223250079Scarl
1224250079Scarl	rc = ntb_write_remote_spad(ntb, IF_NTB_QP_LINKS, val | 1 << qp->qp_num);
1225250079Scarl
1226250079Scarl	/* query remote spad for qp ready bits */
1227250079Scarl	rc = ntb_read_local_spad(ntb, IF_NTB_QP_LINKS, &val);
1228250079Scarl
1229250079Scarl	/* See if the remote side is up */
1230250079Scarl	if ((1 << qp->qp_num & val) != 0) {
1231250079Scarl		qp->qp_link = NTB_LINK_UP;
1232250079Scarl		if (qp->event_handler != NULL)
1233250079Scarl			qp->event_handler(qp->cb_data, NTB_LINK_UP);
1234255268Scarl		if (bootverbose)
1235255268Scarl			device_printf(ntb_get_device(ntb), "qp link up\n");
1236250079Scarl	} else if (nt->transport_link == NTB_LINK_UP) {
1237250079Scarl		callout_reset(&qp->link_work,
1238250079Scarl		    NTB_LINK_DOWN_TIMEOUT * hz / 1000, ntb_qp_link_work, qp);
1239250079Scarl	}
1240250079Scarl}
1241250079Scarl
1242250079Scarl/* Link down event*/
1243250079Scarlstatic void
1244250079Scarlntb_transport_link_cleanup(struct ntb_netdev *nt)
1245250079Scarl{
1246250079Scarl	int i;
1247250079Scarl
1248250079Scarl	if (nt->transport_link == NTB_LINK_DOWN)
1249250079Scarl		callout_drain(&nt->link_work);
1250250079Scarl	else
1251250079Scarl		nt->transport_link = NTB_LINK_DOWN;
1252250079Scarl
1253250079Scarl	/* Pass along the info to any clients */
1254250079Scarl	for (i = 0; i < nt->max_qps; i++)
1255250079Scarl		if (!test_bit(i, &nt->qp_bitmap))
1256250079Scarl			ntb_qp_link_down(&nt->qps[i]);
1257250079Scarl
1258250079Scarl	/*
1259250079Scarl	 * The scratchpad registers keep the values if the remote side
1260250079Scarl	 * goes down, blast them now to give them a sane value the next
1261250079Scarl	 * time they are accessed
1262250079Scarl	 */
1263250079Scarl	for (i = 0; i < IF_NTB_MAX_SPAD; i++)
1264250079Scarl		ntb_write_local_spad(nt->ntb, i, 0);
1265250079Scarl}
1266250079Scarl
1267250079Scarl
1268250079Scarlstatic void
1269250079Scarlntb_qp_link_down(struct ntb_transport_qp *qp)
1270250079Scarl{
1271250079Scarl
1272250079Scarl	ntb_qp_link_cleanup(qp);
1273250079Scarl}
1274250079Scarl
1275250079Scarlstatic void
1276250079Scarlntb_qp_link_cleanup(struct ntb_transport_qp *qp)
1277250079Scarl{
1278250079Scarl	struct ntb_netdev *nt = qp->transport;
1279250079Scarl
1280250079Scarl	if (qp->qp_link == NTB_LINK_DOWN) {
1281250079Scarl		callout_drain(&qp->link_work);
1282250079Scarl		return;
1283250079Scarl	}
1284250079Scarl
1285250079Scarl	if (qp->event_handler != NULL)
1286250079Scarl		qp->event_handler(qp->cb_data, NTB_LINK_DOWN);
1287250079Scarl
1288250079Scarl	qp->qp_link = NTB_LINK_DOWN;
1289250079Scarl
1290250079Scarl	if (nt->transport_link == NTB_LINK_UP)
1291250079Scarl		callout_reset(&qp->link_work,
1292250079Scarl		    NTB_LINK_DOWN_TIMEOUT * hz / 1000, ntb_qp_link_work, qp);
1293250079Scarl}
1294250079Scarl
1295250079Scarl/* Link commanded down */
1296250079Scarl/**
1297250079Scarl * ntb_transport_link_down - Notify NTB transport to no longer enqueue data
1298250079Scarl * @qp: NTB transport layer queue to be disabled
1299250079Scarl *
1300250079Scarl * Notify NTB transport layer of client's desire to no longer receive data on
1301250079Scarl * transport queue specified.  It is the client's responsibility to ensure all
1302250079Scarl * entries on queue are purged or otherwise handled appropraitely.
1303250079Scarl */
1304250079Scarlstatic void
1305250079Scarlntb_transport_link_down(struct ntb_transport_qp *qp)
1306250079Scarl{
1307250079Scarl	int rc, val;
1308250079Scarl
1309250079Scarl	if (qp == NULL)
1310250079Scarl		return;
1311250079Scarl
1312250079Scarl	qp->client_ready = NTB_LINK_DOWN;
1313250079Scarl
1314250079Scarl	rc = ntb_read_remote_spad(qp->ntb, IF_NTB_QP_LINKS, &val);
1315250079Scarl	if (rc != 0)
1316250079Scarl		return;
1317250079Scarl
1318250079Scarl	rc = ntb_write_remote_spad(qp->ntb, IF_NTB_QP_LINKS,
1319250079Scarl	   val & ~(1 << qp->qp_num));
1320250079Scarl
1321250079Scarl	if (qp->qp_link == NTB_LINK_UP)
1322250079Scarl		ntb_send_link_down(qp);
1323250079Scarl	else
1324250079Scarl		callout_drain(&qp->link_work);
1325250079Scarl
1326250079Scarl}
1327250079Scarl
1328250079Scarlstatic void
1329250079Scarlntb_send_link_down(struct ntb_transport_qp *qp)
1330250079Scarl{
1331250079Scarl	struct ntb_queue_entry *entry;
1332250079Scarl	int i, rc;
1333250079Scarl
1334250079Scarl	if (qp->qp_link == NTB_LINK_DOWN)
1335250079Scarl		return;
1336250079Scarl
1337250079Scarl	qp->qp_link = NTB_LINK_DOWN;
1338250079Scarl
1339250079Scarl	for (i = 0; i < NTB_LINK_DOWN_TIMEOUT; i++) {
1340250079Scarl		entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q);
1341250079Scarl		if (entry != NULL)
1342250079Scarl			break;
1343250079Scarl		pause("NTB Wait for link down", hz / 10);
1344250079Scarl	}
1345250079Scarl
1346250079Scarl	if (entry == NULL)
1347250079Scarl		return;
1348250079Scarl
1349250079Scarl	entry->cb_data = NULL;
1350250079Scarl	entry->buf = NULL;
1351250079Scarl	entry->len = 0;
1352250079Scarl	entry->flags = IF_NTB_LINK_DOWN_FLAG;
1353250079Scarl
1354250079Scarl	mtx_lock(&qp->transport->tx_lock);
1355250079Scarl	rc = ntb_process_tx(qp, entry);
1356250079Scarl	if (rc != 0)
1357250079Scarl		printf("ntb: Failed to send link down\n");
1358250079Scarl	mtx_unlock(&qp->transport->tx_lock);
1359250079Scarl}
1360250079Scarl
1361250079Scarl
1362250079Scarl/* List Management */
1363250079Scarl
1364250079Scarlstatic void
1365250079Scarlntb_list_add(struct mtx *lock, struct ntb_queue_entry *entry,
1366250079Scarl    struct ntb_queue_list *list)
1367250079Scarl{
1368250079Scarl
1369250079Scarl	mtx_lock_spin(lock);
1370250079Scarl	STAILQ_INSERT_TAIL(list, entry, entry);
1371250079Scarl	mtx_unlock_spin(lock);
1372250079Scarl}
1373250079Scarl
1374250079Scarlstatic struct ntb_queue_entry *
1375250079Scarlntb_list_rm(struct mtx *lock, struct ntb_queue_list *list)
1376250079Scarl{
1377250079Scarl	struct ntb_queue_entry *entry;
1378250079Scarl
1379250079Scarl	mtx_lock_spin(lock);
1380250079Scarl	if (STAILQ_EMPTY(list)) {
1381250079Scarl		entry = NULL;
1382250079Scarl		goto out;
1383250079Scarl	}
1384250079Scarl	entry = STAILQ_FIRST(list);
1385250079Scarl	STAILQ_REMOVE_HEAD(list, entry);
1386250079Scarlout:
1387250079Scarl	mtx_unlock_spin(lock);
1388250079Scarl
1389250079Scarl	return (entry);
1390250079Scarl}
1391250079Scarl
1392250079Scarl/* Helper functions */
1393250079Scarl/* TODO: This too should really be part of the kernel */
1394250079Scarl#define EUI48_MULTICAST			1 << 0
1395250079Scarl#define EUI48_LOCALLY_ADMINISTERED	1 << 1
1396250079Scarlstatic void
1397250079Scarlcreate_random_local_eui48(u_char *eaddr)
1398250079Scarl{
1399250079Scarl	static uint8_t counter = 0;
1400250079Scarl	uint32_t seed = ticks;
1401250079Scarl
1402250079Scarl	eaddr[0] = EUI48_LOCALLY_ADMINISTERED;
1403250079Scarl	memcpy(&eaddr[1], &seed, sizeof(uint32_t));
1404250079Scarl	eaddr[5] = counter++;
1405250079Scarl}
1406250079Scarl
1407250079Scarl/**
1408250079Scarl * ntb_transport_max_size - Query the max payload size of a qp
1409250079Scarl * @qp: NTB transport layer queue to be queried
1410250079Scarl *
1411250079Scarl * Query the maximum payload size permissible on the given qp
1412250079Scarl *
1413250079Scarl * RETURNS: the max payload size of a qp
1414250079Scarl */
1415250079Scarlstatic unsigned int
1416250079Scarlntb_transport_max_size(struct ntb_transport_qp *qp)
1417250079Scarl{
1418250079Scarl
1419250079Scarl	if (qp == NULL)
1420250079Scarl		return (0);
1421250079Scarl
1422250079Scarl	return (qp->tx_max_frame - sizeof(struct ntb_payload_header));
1423250079Scarl}
1424