ntb_transport.c revision 289273
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 289273 2015-10-13 23:42:13Z 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>
42289207Scem#include <sys/sysctl.h>
43250079Scarl#include <sys/taskqueue.h>
44250079Scarl#include <net/if.h>
45250079Scarl#include <net/if_media.h>
46250079Scarl#include <net/if_types.h>
47250079Scarl#include <net/if_var.h>
48250079Scarl#include <net/bpf.h>
49250079Scarl#include <net/ethernet.h>
50250079Scarl#include <vm/vm.h>
51250079Scarl#include <vm/pmap.h>
52250079Scarl#include <machine/bus.h>
53250079Scarl#include <machine/cpufunc.h>
54250079Scarl#include <machine/pmap.h>
55250079Scarl
56250079Scarl#include "../ntb_hw/ntb_hw.h"
57250079Scarl
58250079Scarl/*
59250079Scarl * The Non-Transparent Bridge (NTB) is a device on some Intel processors that
60250079Scarl * allows you to connect two systems using a PCI-e link.
61250079Scarl *
62250079Scarl * This module contains a protocol for sending and receiving messages, and
63250079Scarl * exposes that protocol through a simulated ethernet device called ntb.
64250079Scarl *
65250079Scarl * NOTE: Much of the code in this module is shared with Linux. Any patches may
66250079Scarl * be picked up and redistributed in Linux with a dual GPL/BSD license.
67250079Scarl */
68250079Scarl
69250079Scarl/* TODO: These functions should really be part of the kernel */
70250079Scarl#define test_bit(pos, bitmap_addr)  (*(bitmap_addr) & 1UL << (pos))
71250079Scarl#define set_bit(pos, bitmap_addr)   *(bitmap_addr) |= 1UL << (pos)
72250079Scarl#define clear_bit(pos, bitmap_addr) *(bitmap_addr) &= ~(1UL << (pos))
73250079Scarl
74250079Scarl#define KTR_NTB KTR_SPARE3
75250079Scarl
76250079Scarl#define NTB_TRANSPORT_VERSION	3
77250079Scarl#define NTB_RX_MAX_PKTS		64
78250079Scarl#define	NTB_RXQ_SIZE		300
79250079Scarl
80250079Scarlstatic unsigned int transport_mtu = 0x4000 + ETHER_HDR_LEN + ETHER_CRC_LEN;
81289208Scem
82289208Scem/*
83289208Scem * This is an oversimplification to work around Xeon Errata.  The second client
84289208Scem * may be usable for unidirectional traffic.
85289208Scem */
86250079Scarlstatic unsigned int max_num_clients = 1;
87250079Scarl
88250079ScarlSTAILQ_HEAD(ntb_queue_list, ntb_queue_entry);
89250079Scarl
90250079Scarlstruct ntb_queue_entry {
91250079Scarl	/* ntb_queue list reference */
92250079Scarl	STAILQ_ENTRY(ntb_queue_entry) entry;
93250079Scarl
94250079Scarl	/* info on data to be transfered */
95250079Scarl	void		*cb_data;
96250079Scarl	void		*buf;
97250079Scarl	uint64_t	len;
98250079Scarl	uint64_t	flags;
99250079Scarl};
100250079Scarl
101250079Scarlstruct ntb_rx_info {
102250079Scarl	unsigned int entry;
103250079Scarl};
104250079Scarl
105250079Scarlstruct ntb_transport_qp {
106250079Scarl	struct ntb_netdev	*transport;
107250079Scarl	struct ntb_softc	*ntb;
108250079Scarl
109250079Scarl	void			*cb_data;
110250079Scarl
111250079Scarl	bool			client_ready;
112250079Scarl	bool			qp_link;
113255281Scarl	uint8_t			qp_num;	/* Only 64 QPs are allowed.  0-63 */
114250079Scarl
115250079Scarl	struct ntb_rx_info	*rx_info;
116250079Scarl	struct ntb_rx_info	*remote_rx_info;
117250079Scarl
118250079Scarl	void (*tx_handler) (struct ntb_transport_qp *qp, void *qp_data,
119250079Scarl	    void *data, int len);
120250079Scarl	struct ntb_queue_list	tx_free_q;
121250079Scarl	struct mtx		ntb_tx_free_q_lock;
122250079Scarl	void			*tx_mw;
123250079Scarl	uint64_t		tx_index;
124250079Scarl	uint64_t		tx_max_entry;
125250079Scarl	uint64_t		tx_max_frame;
126250079Scarl
127250079Scarl	void (*rx_handler) (struct ntb_transport_qp *qp, void *qp_data,
128250079Scarl	    void *data, int len);
129250079Scarl	struct ntb_queue_list	rx_pend_q;
130250079Scarl	struct ntb_queue_list	rx_free_q;
131250079Scarl	struct mtx		ntb_rx_pend_q_lock;
132250079Scarl	struct mtx		ntb_rx_free_q_lock;
133250079Scarl	struct task		rx_completion_task;
134250079Scarl	void			*rx_buff;
135250079Scarl	uint64_t		rx_index;
136250079Scarl	uint64_t		rx_max_entry;
137250079Scarl	uint64_t		rx_max_frame;
138250079Scarl
139250079Scarl	void (*event_handler) (void *data, int status);
140250079Scarl	struct callout		link_work;
141250079Scarl	struct callout		queue_full;
142250079Scarl	struct callout		rx_full;
143250079Scarl
144250079Scarl	uint64_t		last_rx_no_buf;
145250079Scarl
146250079Scarl	/* Stats */
147250079Scarl	uint64_t		rx_bytes;
148250079Scarl	uint64_t		rx_pkts;
149250079Scarl	uint64_t		rx_ring_empty;
150250079Scarl	uint64_t		rx_err_no_buf;
151250079Scarl	uint64_t		rx_err_oflow;
152250079Scarl	uint64_t		rx_err_ver;
153250079Scarl	uint64_t		tx_bytes;
154250079Scarl	uint64_t		tx_pkts;
155250079Scarl	uint64_t		tx_ring_full;
156250079Scarl};
157250079Scarl
158250079Scarlstruct ntb_queue_handlers {
159250079Scarl	void (*rx_handler) (struct ntb_transport_qp *qp, void *qp_data,
160250079Scarl	    void *data, int len);
161250079Scarl	void (*tx_handler) (struct ntb_transport_qp *qp, void *qp_data,
162250079Scarl	    void *data, int len);
163250079Scarl	void (*event_handler) (void *data, int status);
164250079Scarl};
165250079Scarl
166250079Scarl
167250079Scarlstruct ntb_transport_mw {
168250079Scarl	size_t		size;
169250079Scarl	void		*virt_addr;
170250079Scarl	vm_paddr_t	dma_addr;
171250079Scarl};
172250079Scarl
173250079Scarlstruct ntb_netdev {
174250079Scarl	struct ntb_softc	*ntb;
175250079Scarl	struct ifnet		*ifp;
176250079Scarl	struct ntb_transport_mw	mw[NTB_NUM_MW];
177250079Scarl	struct ntb_transport_qp	*qps;
178250079Scarl	uint64_t		max_qps;
179250079Scarl	uint64_t		qp_bitmap;
180250079Scarl	bool			transport_link;
181250079Scarl	struct callout		link_work;
182250079Scarl	struct ntb_transport_qp *qp;
183250079Scarl	uint64_t		bufsize;
184250079Scarl	u_char			eaddr[ETHER_ADDR_LEN];
185250079Scarl	struct mtx		tx_lock;
186250079Scarl	struct mtx		rx_lock;
187250079Scarl};
188250079Scarl
189250079Scarlstatic struct ntb_netdev net_softc;
190250079Scarl
191250079Scarlenum {
192250079Scarl	IF_NTB_DESC_DONE_FLAG = 1 << 0,
193250079Scarl	IF_NTB_LINK_DOWN_FLAG = 1 << 1,
194250079Scarl};
195250079Scarl
196250079Scarlstruct ntb_payload_header {
197250079Scarl	uint64_t ver;
198250079Scarl	uint64_t len;
199250079Scarl	uint64_t flags;
200250079Scarl};
201250079Scarl
202250079Scarlenum {
203289153Scem	/*
204289153Scem	 * The order of this enum is part of the if_ntb remote protocol.  Do
205289153Scem	 * not reorder without bumping protocol version (and it's probably best
206289153Scem	 * to keep the protocol in lock-step with the Linux NTB driver.
207289153Scem	 */
208250079Scarl	IF_NTB_VERSION = 0,
209289153Scem	IF_NTB_QP_LINKS,
210250079Scarl	IF_NTB_NUM_QPS,
211289153Scem	IF_NTB_NUM_MWS,
212289153Scem	/*
213289153Scem	 * N.B.: transport_link_work assumes MW1 enums = MW0 + 2.
214289153Scem	 */
215289153Scem	IF_NTB_MW0_SZ_HIGH,
216289153Scem	IF_NTB_MW0_SZ_LOW,
217289153Scem	IF_NTB_MW1_SZ_HIGH,
218289153Scem	IF_NTB_MW1_SZ_LOW,
219250079Scarl	IF_NTB_MAX_SPAD,
220250079Scarl};
221250079Scarl
222250079Scarl#define QP_TO_MW(qp)		((qp) % NTB_NUM_MW)
223250079Scarl#define NTB_QP_DEF_NUM_ENTRIES	100
224250079Scarl#define NTB_LINK_DOWN_TIMEOUT	10
225250079Scarl
226250079Scarlstatic int ntb_handle_module_events(struct module *m, int what, void *arg);
227250079Scarlstatic int ntb_setup_interface(void);
228250079Scarlstatic int ntb_teardown_interface(void);
229250079Scarlstatic void ntb_net_init(void *arg);
230250079Scarlstatic int ntb_ioctl(struct ifnet *ifp, u_long command, caddr_t data);
231250079Scarlstatic void ntb_start(struct ifnet *ifp);
232250079Scarlstatic void ntb_net_tx_handler(struct ntb_transport_qp *qp, void *qp_data,
233250079Scarl    void *data, int len);
234250079Scarlstatic void ntb_net_rx_handler(struct ntb_transport_qp *qp, void *qp_data,
235250079Scarl    void *data, int len);
236250079Scarlstatic void ntb_net_event_handler(void *data, int status);
237250079Scarlstatic int ntb_transport_init(struct ntb_softc *ntb);
238250079Scarlstatic void ntb_transport_free(void *transport);
239250079Scarlstatic void ntb_transport_init_queue(struct ntb_netdev *nt,
240250079Scarl    unsigned int qp_num);
241250079Scarlstatic void ntb_transport_free_queue(struct ntb_transport_qp *qp);
242250079Scarlstatic struct ntb_transport_qp * ntb_transport_create_queue(void *data,
243250079Scarl    struct ntb_softc *pdev, const struct ntb_queue_handlers *handlers);
244250079Scarlstatic void ntb_transport_link_up(struct ntb_transport_qp *qp);
245250079Scarlstatic int ntb_transport_tx_enqueue(struct ntb_transport_qp *qp, void *cb,
246250079Scarl    void *data, unsigned int len);
247250079Scarlstatic int ntb_process_tx(struct ntb_transport_qp *qp,
248250079Scarl    struct ntb_queue_entry *entry);
249250079Scarlstatic void ntb_tx_copy_task(struct ntb_transport_qp *qp,
250250079Scarl    struct ntb_queue_entry *entry, void *offset);
251250079Scarlstatic void ntb_qp_full(void *arg);
252250079Scarlstatic void ntb_transport_rxc_db(void *data, int db_num);
253250079Scarlstatic void ntb_rx_pendq_full(void *arg);
254250079Scarlstatic void ntb_transport_rx(struct ntb_transport_qp *qp);
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
468250079Scarlntb_net_event_handler(void *data, int status)
469250079Scarl{
470250079Scarl
471250079Scarl}
472250079Scarl
473250079Scarl/* Transport Init and teardown */
474250079Scarl
475250079Scarlstatic int
476250079Scarlntb_transport_init(struct ntb_softc *ntb)
477250079Scarl{
478250079Scarl	struct ntb_netdev *nt = &net_softc;
479250079Scarl	int rc, i;
480250079Scarl
481250079Scarl	nt->max_qps = max_num_clients;
482250079Scarl	ntb_register_transport(ntb, nt);
483250079Scarl	mtx_init(&nt->tx_lock, "ntb transport tx", NULL, MTX_DEF);
484250079Scarl	mtx_init(&nt->rx_lock, "ntb transport rx", NULL, MTX_DEF);
485250079Scarl
486250079Scarl	nt->qps = malloc(nt->max_qps * sizeof(struct ntb_transport_qp),
487250079Scarl			  M_NTB_IF, M_WAITOK|M_ZERO);
488250079Scarl
489250079Scarl	nt->qp_bitmap = ((uint64_t) 1 << nt->max_qps) - 1;
490250079Scarl
491250079Scarl	for (i = 0; i < nt->max_qps; i++)
492250079Scarl		ntb_transport_init_queue(nt, i);
493250079Scarl
494250079Scarl	callout_init(&nt->link_work, 0);
495250079Scarl
496250079Scarl	rc = ntb_register_event_callback(ntb,
497250079Scarl					 ntb_transport_event_callback);
498250079Scarl	if (rc != 0)
499250079Scarl		goto err;
500250079Scarl
501255268Scarl	if (ntb_query_link_status(ntb)) {
502255268Scarl		if (bootverbose)
503255268Scarl			device_printf(ntb_get_device(ntb), "link up\n");
504250079Scarl		callout_reset(&nt->link_work, 0, ntb_transport_link_work, nt);
505255268Scarl	}
506250079Scarl
507250079Scarl	return (0);
508250079Scarl
509250079Scarlerr:
510250079Scarl	free(nt->qps, M_NTB_IF);
511250079Scarl	ntb_unregister_transport(ntb);
512250079Scarl	return (rc);
513250079Scarl}
514250079Scarl
515250079Scarlstatic void
516250079Scarlntb_transport_free(void *transport)
517250079Scarl{
518250079Scarl	struct ntb_netdev *nt = transport;
519250079Scarl	struct ntb_softc *ntb = nt->ntb;
520250079Scarl	int i;
521250079Scarl
522289273Scem	ntb_transport_link_cleanup(nt);
523250079Scarl
524250079Scarl	callout_drain(&nt->link_work);
525250079Scarl
526255281Scarl	/* verify that all the qps are freed */
527250079Scarl	for (i = 0; i < nt->max_qps; i++)
528250079Scarl		if (!test_bit(i, &nt->qp_bitmap))
529250079Scarl			ntb_transport_free_queue(&nt->qps[i]);
530250079Scarl
531250079Scarl	ntb_unregister_event_callback(ntb);
532250079Scarl
533250079Scarl	for (i = 0; i < NTB_NUM_MW; i++)
534289153Scem		ntb_free_mw(nt, i);
535250079Scarl
536250079Scarl	free(nt->qps, M_NTB_IF);
537250079Scarl	ntb_unregister_transport(ntb);
538250079Scarl}
539250079Scarl
540250079Scarlstatic void
541250079Scarlntb_transport_init_queue(struct ntb_netdev *nt, unsigned int qp_num)
542250079Scarl{
543250079Scarl	struct ntb_transport_qp *qp;
544250079Scarl	unsigned int num_qps_mw, tx_size;
545250079Scarl	uint8_t mw_num = QP_TO_MW(qp_num);
546250079Scarl
547250079Scarl	qp = &nt->qps[qp_num];
548250079Scarl	qp->qp_num = qp_num;
549250079Scarl	qp->transport = nt;
550250079Scarl	qp->ntb = nt->ntb;
551250079Scarl	qp->qp_link = NTB_LINK_DOWN;
552250079Scarl	qp->client_ready = NTB_LINK_DOWN;
553250079Scarl	qp->event_handler = NULL;
554250079Scarl
555250079Scarl	if (nt->max_qps % NTB_NUM_MW && mw_num < nt->max_qps % NTB_NUM_MW)
556250079Scarl		num_qps_mw = nt->max_qps / NTB_NUM_MW + 1;
557250079Scarl	else
558250079Scarl		num_qps_mw = nt->max_qps / NTB_NUM_MW;
559250079Scarl
560250079Scarl	tx_size = (unsigned int) ntb_get_mw_size(qp->ntb, mw_num) / num_qps_mw;
561250079Scarl	qp->rx_info = (struct ntb_rx_info *)
562250079Scarl	    ((char *)ntb_get_mw_vbase(qp->ntb, mw_num) +
563250079Scarl	    (qp_num / NTB_NUM_MW * tx_size));
564250079Scarl	tx_size -= sizeof(struct ntb_rx_info);
565250079Scarl
566289152Scem	qp->tx_mw = qp->rx_info + 1;
567289156Scem	/* Due to house-keeping, there must be at least 2 buffs */
568250079Scarl	qp->tx_max_frame = min(transport_mtu + sizeof(struct ntb_payload_header),
569289156Scem	    tx_size / 2);
570250079Scarl	qp->tx_max_entry = tx_size / qp->tx_max_frame;
571250079Scarl
572250079Scarl	callout_init(&qp->link_work, 0);
573283291Sjkim	callout_init(&qp->queue_full, 1);
574283291Sjkim	callout_init(&qp->rx_full, 1);
575250079Scarl
576250079Scarl	mtx_init(&qp->ntb_rx_pend_q_lock, "ntb rx pend q", NULL, MTX_SPIN);
577250079Scarl	mtx_init(&qp->ntb_rx_free_q_lock, "ntb rx free q", NULL, MTX_SPIN);
578250079Scarl	mtx_init(&qp->ntb_tx_free_q_lock, "ntb tx free q", NULL, MTX_SPIN);
579250079Scarl	TASK_INIT(&qp->rx_completion_task, 0, ntb_rx_completion_task, qp);
580250079Scarl
581250079Scarl	STAILQ_INIT(&qp->rx_pend_q);
582250079Scarl	STAILQ_INIT(&qp->rx_free_q);
583250079Scarl	STAILQ_INIT(&qp->tx_free_q);
584250079Scarl}
585250079Scarl
586250079Scarlstatic void
587250079Scarlntb_transport_free_queue(struct ntb_transport_qp *qp)
588250079Scarl{
589250079Scarl	struct ntb_queue_entry *entry;
590250079Scarl
591250079Scarl	if (qp == NULL)
592250079Scarl		return;
593250079Scarl
594250079Scarl	callout_drain(&qp->link_work);
595250079Scarl
596250079Scarl	ntb_unregister_db_callback(qp->ntb, qp->qp_num);
597250079Scarl
598250079Scarl	while ((entry = ntb_list_rm(&qp->ntb_rx_free_q_lock, &qp->rx_free_q)))
599250079Scarl		free(entry, M_NTB_IF);
600250079Scarl
601250079Scarl	while ((entry = ntb_list_rm(&qp->ntb_rx_pend_q_lock, &qp->rx_pend_q)))
602250079Scarl		free(entry, M_NTB_IF);
603250079Scarl
604250079Scarl	while ((entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q)))
605250079Scarl		free(entry, M_NTB_IF);
606250079Scarl
607250079Scarl	set_bit(qp->qp_num, &qp->transport->qp_bitmap);
608250079Scarl}
609250079Scarl
610250079Scarl/**
611250079Scarl * ntb_transport_create_queue - Create a new NTB transport layer queue
612250079Scarl * @rx_handler: receive callback function
613250079Scarl * @tx_handler: transmit callback function
614250079Scarl * @event_handler: event callback function
615250079Scarl *
616250079Scarl * Create a new NTB transport layer queue and provide the queue with a callback
617250079Scarl * routine for both transmit and receive.  The receive callback routine will be
618250079Scarl * used to pass up data when the transport has received it on the queue.   The
619250079Scarl * transmit callback routine will be called when the transport has completed the
620250079Scarl * transmission of the data on the queue and the data is ready to be freed.
621250079Scarl *
622250079Scarl * RETURNS: pointer to newly created ntb_queue, NULL on error.
623250079Scarl */
624250079Scarlstatic struct ntb_transport_qp *
625250079Scarlntb_transport_create_queue(void *data, struct ntb_softc *pdev,
626250079Scarl    const struct ntb_queue_handlers *handlers)
627250079Scarl{
628250079Scarl	struct ntb_queue_entry *entry;
629250079Scarl	struct ntb_transport_qp *qp;
630250079Scarl	struct ntb_netdev *nt;
631250079Scarl	unsigned int free_queue;
632250079Scarl	int rc, i;
633250079Scarl
634250079Scarl	nt = ntb_find_transport(pdev);
635250079Scarl	if (nt == NULL)
636250079Scarl		goto err;
637250079Scarl
638250079Scarl	free_queue = ffs(nt->qp_bitmap);
639250079Scarl	if (free_queue == 0)
640250079Scarl		goto err;
641250079Scarl
642250079Scarl	/* decrement free_queue to make it zero based */
643250079Scarl	free_queue--;
644250079Scarl
645250079Scarl	clear_bit(free_queue, &nt->qp_bitmap);
646250079Scarl
647250079Scarl	qp = &nt->qps[free_queue];
648250079Scarl	qp->cb_data = data;
649250079Scarl	qp->rx_handler = handlers->rx_handler;
650250079Scarl	qp->tx_handler = handlers->tx_handler;
651250079Scarl	qp->event_handler = handlers->event_handler;
652250079Scarl
653250079Scarl	for (i = 0; i < NTB_QP_DEF_NUM_ENTRIES; i++) {
654250079Scarl		entry = malloc(sizeof(struct ntb_queue_entry), M_NTB_IF,
655250079Scarl		    M_WAITOK|M_ZERO);
656250079Scarl		entry->cb_data = nt->ifp;
657250079Scarl		entry->buf = NULL;
658250079Scarl		entry->len = transport_mtu;
659250079Scarl		ntb_list_add(&qp->ntb_rx_pend_q_lock, entry, &qp->rx_pend_q);
660250079Scarl	}
661250079Scarl
662250079Scarl	for (i = 0; i < NTB_QP_DEF_NUM_ENTRIES; i++) {
663250079Scarl		entry = malloc(sizeof(struct ntb_queue_entry), M_NTB_IF,
664250079Scarl		    M_WAITOK|M_ZERO);
665250079Scarl		ntb_list_add(&qp->ntb_tx_free_q_lock, entry, &qp->tx_free_q);
666250079Scarl	}
667250079Scarl
668250079Scarl	rc = ntb_register_db_callback(qp->ntb, free_queue, qp,
669250079Scarl				      ntb_transport_rxc_db);
670250079Scarl	if (rc != 0)
671250079Scarl		goto err1;
672250079Scarl
673250079Scarl	return (qp);
674250079Scarl
675250079Scarlerr1:
676250079Scarl	while ((entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q)))
677250079Scarl		free(entry, M_NTB_IF);
678250079Scarl	while ((entry = ntb_list_rm(&qp->ntb_rx_free_q_lock, &qp->rx_free_q)))
679250079Scarl		free(entry, M_NTB_IF);
680250079Scarl	set_bit(free_queue, &nt->qp_bitmap);
681250079Scarlerr:
682250079Scarl	return (NULL);
683250079Scarl}
684250079Scarl
685250079Scarl/**
686250079Scarl * ntb_transport_link_up - Notify NTB transport of client readiness to use queue
687250079Scarl * @qp: NTB transport layer queue to be enabled
688250079Scarl *
689250079Scarl * Notify NTB transport layer of client readiness to use queue
690250079Scarl */
691250079Scarlstatic void
692250079Scarlntb_transport_link_up(struct ntb_transport_qp *qp)
693250079Scarl{
694250079Scarl
695250079Scarl	if (qp == NULL)
696250079Scarl		return;
697250079Scarl
698250079Scarl	qp->client_ready = NTB_LINK_UP;
699255268Scarl	if (bootverbose)
700255268Scarl		device_printf(ntb_get_device(qp->ntb), "qp client ready\n");
701250079Scarl
702250079Scarl	if (qp->transport->transport_link == NTB_LINK_UP)
703250079Scarl		callout_reset(&qp->link_work, 0, ntb_qp_link_work, qp);
704250079Scarl}
705250079Scarl
706250079Scarl
707250079Scarl
708250079Scarl/* Transport Tx */
709250079Scarl
710250079Scarl/**
711250079Scarl * ntb_transport_tx_enqueue - Enqueue a new NTB queue entry
712250079Scarl * @qp: NTB transport layer queue the entry is to be enqueued on
713250079Scarl * @cb: per buffer pointer for callback function to use
714250079Scarl * @data: pointer to data buffer that will be sent
715250079Scarl * @len: length of the data buffer
716250079Scarl *
717250079Scarl * Enqueue a new transmit buffer onto the transport queue from which a NTB
718289266Scem * payload will be transmitted.  This assumes that a lock is being held to
719250079Scarl * serialize access to the qp.
720250079Scarl *
721250079Scarl * RETURNS: An appropriate ERRNO error value on error, or zero for success.
722250079Scarl */
723250079Scarlstatic int
724250079Scarlntb_transport_tx_enqueue(struct ntb_transport_qp *qp, void *cb, void *data,
725250079Scarl    unsigned int len)
726250079Scarl{
727250079Scarl	struct ntb_queue_entry *entry;
728250079Scarl	int rc;
729250079Scarl
730250079Scarl	if (qp == NULL || qp->qp_link != NTB_LINK_UP || len == 0) {
731250079Scarl		CTR0(KTR_NTB, "TX: link not up");
732250079Scarl		return (EINVAL);
733250079Scarl	}
734250079Scarl
735250079Scarl	entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q);
736250079Scarl	if (entry == NULL) {
737255281Scarl		CTR0(KTR_NTB, "TX: could not get entry from tx_free_q");
738250079Scarl		return (ENOMEM);
739250079Scarl	}
740250079Scarl	CTR1(KTR_NTB, "TX: got entry %p from tx_free_q", entry);
741250079Scarl
742250079Scarl	entry->cb_data = cb;
743250079Scarl	entry->buf = data;
744250079Scarl	entry->len = len;
745250079Scarl	entry->flags = 0;
746250079Scarl
747250079Scarl	rc = ntb_process_tx(qp, entry);
748250079Scarl	if (rc != 0) {
749250079Scarl		ntb_list_add(&qp->ntb_tx_free_q_lock, entry, &qp->tx_free_q);
750250079Scarl		CTR1(KTR_NTB,
751250079Scarl		    "TX: process_tx failed. Returning entry %p to tx_free_q",
752250079Scarl		    entry);
753250079Scarl	}
754250079Scarl	return (rc);
755250079Scarl}
756250079Scarl
757250079Scarlstatic int
758250079Scarlntb_process_tx(struct ntb_transport_qp *qp, struct ntb_queue_entry *entry)
759250079Scarl{
760250079Scarl	void *offset;
761250079Scarl
762250079Scarl	offset = (char *)qp->tx_mw + qp->tx_max_frame * qp->tx_index;
763250079Scarl	CTR3(KTR_NTB,
764250079Scarl	    "TX: process_tx: tx_pkts=%u, tx_index=%u, remote entry=%u",
765250079Scarl	    qp->tx_pkts, qp->tx_index, qp->remote_rx_info->entry);
766250079Scarl	if (qp->tx_index == qp->remote_rx_info->entry) {
767250079Scarl		CTR0(KTR_NTB, "TX: ring full");
768250079Scarl		qp->tx_ring_full++;
769250079Scarl		return (EAGAIN);
770250079Scarl	}
771250079Scarl
772250079Scarl	if (entry->len > qp->tx_max_frame - sizeof(struct ntb_payload_header)) {
773250079Scarl		if (qp->tx_handler != NULL)
774250079Scarl			qp->tx_handler(qp, qp->cb_data, entry->buf,
775250079Scarl				       EIO);
776250079Scarl
777250079Scarl		ntb_list_add(&qp->ntb_tx_free_q_lock, entry, &qp->tx_free_q);
778250079Scarl		CTR1(KTR_NTB,
779250079Scarl		    "TX: frame too big. returning entry %p to tx_free_q",
780250079Scarl		    entry);
781250079Scarl		return (0);
782250079Scarl	}
783250079Scarl	CTR2(KTR_NTB, "TX: copying entry %p to offset %p", entry, offset);
784250079Scarl	ntb_tx_copy_task(qp, entry, offset);
785250079Scarl
786250079Scarl	qp->tx_index++;
787250079Scarl	qp->tx_index %= qp->tx_max_entry;
788250079Scarl
789250079Scarl	qp->tx_pkts++;
790250079Scarl
791250079Scarl	return (0);
792250079Scarl}
793250079Scarl
794250079Scarlstatic void
795250079Scarlntb_tx_copy_task(struct ntb_transport_qp *qp, struct ntb_queue_entry *entry,
796250079Scarl    void *offset)
797250079Scarl{
798250079Scarl	struct ntb_payload_header *hdr;
799250079Scarl
800250079Scarl	CTR2(KTR_NTB, "TX: copying %d bytes to offset %p", entry->len, offset);
801250079Scarl	if (entry->buf != NULL)
802250079Scarl		m_copydata((struct mbuf *)entry->buf, 0, entry->len, offset);
803250079Scarl
804250079Scarl	hdr = (struct ntb_payload_header *)((char *)offset + qp->tx_max_frame -
805250079Scarl	    sizeof(struct ntb_payload_header));
806250079Scarl	hdr->len = entry->len; /* TODO: replace with bus_space_write */
807250079Scarl	hdr->ver = qp->tx_pkts; /* TODO: replace with bus_space_write */
808250079Scarl	wmb();
809250079Scarl	/* TODO: replace with bus_space_write */
810250079Scarl	hdr->flags = entry->flags | IF_NTB_DESC_DONE_FLAG;
811250079Scarl
812289255Scem	ntb_ring_doorbell(qp->ntb, qp->qp_num);
813250079Scarl
814250079Scarl	/*
815250079Scarl	 * The entry length can only be zero if the packet is intended to be a
816250079Scarl	 * "link down" or similar.  Since no payload is being sent in these
817250079Scarl	 * cases, there is nothing to add to the completion queue.
818250079Scarl	 */
819250079Scarl	if (entry->len > 0) {
820250079Scarl		qp->tx_bytes += entry->len;
821250079Scarl
822250079Scarl		if (qp->tx_handler)
823250079Scarl			qp->tx_handler(qp, qp->cb_data, entry->cb_data,
824250079Scarl				       entry->len);
825250079Scarl	}
826250079Scarl
827250079Scarl	CTR2(KTR_NTB,
828250079Scarl	    "TX: entry %p sent. hdr->ver = %d, Returning to tx_free_q", entry,
829250079Scarl	    hdr->ver);
830250079Scarl	ntb_list_add(&qp->ntb_tx_free_q_lock, entry, &qp->tx_free_q);
831250079Scarl}
832250079Scarl
833250079Scarlstatic void
834250079Scarlntb_qp_full(void *arg)
835250079Scarl{
836250079Scarl
837250079Scarl	CTR0(KTR_NTB, "TX: qp_full callout");
838250079Scarl	ntb_start(arg);
839250079Scarl}
840250079Scarl
841250079Scarl/* Transport Rx */
842250079Scarlstatic void
843250079Scarlntb_transport_rxc_db(void *data, int db_num)
844250079Scarl{
845250079Scarl	struct ntb_transport_qp *qp = data;
846250079Scarl
847250079Scarl	ntb_transport_rx(qp);
848250079Scarl}
849250079Scarl
850250079Scarlstatic void
851250079Scarlntb_rx_pendq_full(void *arg)
852250079Scarl{
853250079Scarl
854250079Scarl	CTR0(KTR_NTB, "RX: ntb_rx_pendq_full callout");
855250079Scarl	ntb_transport_rx(arg);
856250079Scarl}
857250079Scarl
858250079Scarlstatic void
859250079Scarlntb_transport_rx(struct ntb_transport_qp *qp)
860250079Scarl{
861289157Scem	uint64_t i;
862289157Scem	int rc;
863250079Scarl
864250079Scarl	/*
865250079Scarl	 * Limit the number of packets processed in a single interrupt to
866250079Scarl	 * provide fairness to others
867250079Scarl	 */
868250079Scarl	mtx_lock(&qp->transport->rx_lock);
869250079Scarl	CTR0(KTR_NTB, "RX: transport_rx");
870289157Scem	for (i = 0; i < qp->rx_max_entry; i++) {
871250079Scarl		rc = ntb_process_rxc(qp);
872250079Scarl		if (rc != 0) {
873250079Scarl			CTR0(KTR_NTB, "RX: process_rxc failed");
874250079Scarl			break;
875250079Scarl		}
876250079Scarl	}
877250079Scarl	mtx_unlock(&qp->transport->rx_lock);
878250079Scarl}
879250079Scarl
880250079Scarlstatic int
881250079Scarlntb_process_rxc(struct ntb_transport_qp *qp)
882250079Scarl{
883250079Scarl	struct ntb_payload_header *hdr;
884250079Scarl	struct ntb_queue_entry *entry;
885250079Scarl	void *offset;
886250079Scarl
887250079Scarl	offset = (void *)
888250079Scarl	    ((char *)qp->rx_buff + qp->rx_max_frame * qp->rx_index);
889250079Scarl	hdr = (void *)
890250079Scarl	    ((char *)offset + qp->rx_max_frame -
891250079Scarl		sizeof(struct ntb_payload_header));
892250079Scarl
893250079Scarl	CTR1(KTR_NTB, "RX: process_rxc rx_index = %u", qp->rx_index);
894250079Scarl	entry = ntb_list_rm(&qp->ntb_rx_pend_q_lock, &qp->rx_pend_q);
895250079Scarl	if (entry == NULL) {
896250079Scarl		qp->rx_err_no_buf++;
897250079Scarl		CTR0(KTR_NTB, "RX: No entries in rx_pend_q");
898250079Scarl		return (ENOMEM);
899250079Scarl	}
900250079Scarl	callout_stop(&qp->rx_full);
901250079Scarl	CTR1(KTR_NTB, "RX: rx entry %p from rx_pend_q", entry);
902250079Scarl
903250079Scarl	if ((hdr->flags & IF_NTB_DESC_DONE_FLAG) == 0) {
904250079Scarl		CTR1(KTR_NTB,
905250079Scarl		    "RX: hdr not done. Returning entry %p to rx_pend_q", entry);
906250079Scarl		ntb_list_add(&qp->ntb_rx_pend_q_lock, entry, &qp->rx_pend_q);
907250079Scarl		qp->rx_ring_empty++;
908250079Scarl		return (EAGAIN);
909250079Scarl	}
910250079Scarl
911250079Scarl	if (hdr->ver != (uint32_t) qp->rx_pkts) {
912250079Scarl		CTR3(KTR_NTB,"RX: ver != rx_pkts (%x != %lx). "
913250079Scarl		    "Returning entry %p to rx_pend_q", hdr->ver, qp->rx_pkts,
914250079Scarl		    entry);
915250079Scarl		ntb_list_add(&qp->ntb_rx_pend_q_lock, entry, &qp->rx_pend_q);
916250079Scarl		qp->rx_err_ver++;
917250079Scarl		return (EIO);
918250079Scarl	}
919250079Scarl
920250079Scarl	if ((hdr->flags & IF_NTB_LINK_DOWN_FLAG) != 0) {
921250079Scarl		ntb_qp_link_down(qp);
922250079Scarl		CTR1(KTR_NTB,
923250079Scarl		    "RX: link down. adding entry %p back to rx_pend_q", entry);
924250079Scarl		ntb_list_add(&qp->ntb_rx_pend_q_lock, entry, &qp->rx_pend_q);
925250079Scarl		goto out;
926250079Scarl	}
927250079Scarl
928250079Scarl	if (hdr->len <= entry->len) {
929250079Scarl		entry->len = hdr->len;
930250079Scarl		ntb_rx_copy_task(qp, entry, offset);
931250079Scarl	} else {
932250079Scarl		CTR1(KTR_NTB,
933250079Scarl		    "RX: len too long. Returning entry %p to rx_pend_q", entry);
934250079Scarl		ntb_list_add(&qp->ntb_rx_pend_q_lock, entry, &qp->rx_pend_q);
935250079Scarl
936250079Scarl		qp->rx_err_oflow++;
937250079Scarl	}
938250079Scarl
939250079Scarl	qp->rx_bytes += hdr->len;
940250079Scarl	qp->rx_pkts++;
941250079Scarl	CTR1(KTR_NTB, "RX: received %ld rx_pkts", qp->rx_pkts);
942250079Scarl
943250079Scarl
944250079Scarlout:
945250079Scarl	/* Ensure that the data is globally visible before clearing the flag */
946250079Scarl	wmb();
947250079Scarl	hdr->flags = 0;
948250079Scarl	/* TODO: replace with bus_space_write */
949250079Scarl	qp->rx_info->entry = qp->rx_index;
950250079Scarl
951250079Scarl	qp->rx_index++;
952250079Scarl	qp->rx_index %= qp->rx_max_entry;
953250079Scarl
954250079Scarl	return (0);
955250079Scarl}
956250079Scarl
957250079Scarlstatic void
958250079Scarlntb_rx_copy_task(struct ntb_transport_qp *qp, struct ntb_queue_entry *entry,
959250079Scarl    void *offset)
960250079Scarl{
961250079Scarl	struct ifnet *ifp = entry->cb_data;
962250079Scarl	unsigned int len = entry->len;
963250079Scarl	struct mbuf *m;
964250079Scarl
965250079Scarl	CTR2(KTR_NTB, "RX: copying %d bytes from offset %p", len, offset);
966250079Scarl	m = m_devget(offset, len, 0, ifp, NULL);
967250079Scarl	m->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID;
968250079Scarl
969250079Scarl	entry->buf = (void *)m;
970250079Scarl
971250079Scarl	CTR2(KTR_NTB,
972250079Scarl	    "RX: copied entry %p to mbuf %p. Adding entry to rx_free_q", entry,
973250079Scarl	    m);
974250079Scarl	ntb_list_add(&qp->ntb_rx_free_q_lock, entry, &qp->rx_free_q);
975250079Scarl
976250079Scarl	taskqueue_enqueue(taskqueue_swi, &qp->rx_completion_task);
977250079Scarl}
978250079Scarl
979250079Scarlstatic void
980250079Scarlntb_rx_completion_task(void *arg, int pending)
981250079Scarl{
982250079Scarl	struct ntb_transport_qp *qp = arg;
983250079Scarl	struct mbuf *m;
984250079Scarl	struct ntb_queue_entry *entry;
985250079Scarl
986250079Scarl	CTR0(KTR_NTB, "RX: rx_completion_task");
987250079Scarl
988250079Scarl	while ((entry = ntb_list_rm(&qp->ntb_rx_free_q_lock, &qp->rx_free_q))) {
989250079Scarl		m = entry->buf;
990250079Scarl		CTR2(KTR_NTB, "RX: completing entry %p, mbuf %p", entry, m);
991250079Scarl		if (qp->rx_handler && qp->client_ready == NTB_LINK_UP)
992250079Scarl			qp->rx_handler(qp, qp->cb_data, m, entry->len);
993250079Scarl
994250079Scarl		entry->buf = NULL;
995250079Scarl		entry->len = qp->transport->bufsize;
996250079Scarl
997250079Scarl		CTR1(KTR_NTB,"RX: entry %p removed from rx_free_q "
998250079Scarl		    "and added to rx_pend_q", entry);
999250079Scarl		ntb_list_add(&qp->ntb_rx_pend_q_lock, entry, &qp->rx_pend_q);
1000250079Scarl		if (qp->rx_err_no_buf > qp->last_rx_no_buf) {
1001250079Scarl			qp->last_rx_no_buf = qp->rx_err_no_buf;
1002250079Scarl			CTR0(KTR_NTB, "RX: could spawn rx task");
1003250079Scarl			callout_reset(&qp->rx_full, hz / 1000, ntb_rx_pendq_full,
1004250079Scarl			    qp);
1005250079Scarl		}
1006250079Scarl	}
1007250079Scarl}
1008250079Scarl
1009250079Scarl/* Link Event handler */
1010250079Scarlstatic void
1011250079Scarlntb_transport_event_callback(void *data, enum ntb_hw_event event)
1012250079Scarl{
1013250079Scarl	struct ntb_netdev *nt = data;
1014250079Scarl
1015250079Scarl	switch (event) {
1016250079Scarl	case NTB_EVENT_HW_LINK_UP:
1017255268Scarl		if (bootverbose)
1018255268Scarl			device_printf(ntb_get_device(nt->ntb), "HW link up\n");
1019250079Scarl		callout_reset(&nt->link_work, 0, ntb_transport_link_work, nt);
1020250079Scarl		break;
1021250079Scarl	case NTB_EVENT_HW_LINK_DOWN:
1022255268Scarl		if (bootverbose)
1023255268Scarl			device_printf(ntb_get_device(nt->ntb), "HW link down\n");
1024250079Scarl		ntb_transport_link_cleanup(nt);
1025250079Scarl		break;
1026250079Scarl	default:
1027250079Scarl		panic("ntb: Unknown NTB event");
1028250079Scarl	}
1029250079Scarl}
1030250079Scarl
1031250079Scarl/* Link bring up */
1032250079Scarlstatic void
1033250079Scarlntb_transport_link_work(void *arg)
1034250079Scarl{
1035250079Scarl	struct ntb_netdev *nt = arg;
1036250079Scarl	struct ntb_softc *ntb = nt->ntb;
1037250079Scarl	struct ntb_transport_qp *qp;
1038289153Scem	uint64_t val64;
1039289208Scem	uint32_t val, i, num_mw;
1040289208Scem	int rc;
1041250079Scarl
1042289208Scem	if (ntb_has_feature(ntb, NTB_REGS_THRU_MW))
1043289208Scem		num_mw = NTB_NUM_MW - 1;
1044289208Scem	else
1045289208Scem		num_mw = NTB_NUM_MW;
1046289208Scem
1047289153Scem	/* send the local info, in the opposite order of the way we read it */
1048289208Scem	for (i = 0; i < num_mw; i++) {
1049289153Scem		rc = ntb_write_remote_spad(ntb, IF_NTB_MW0_SZ_HIGH + (i * 2),
1050289259Scem		    (uint64_t)ntb_get_mw_size(ntb, i) >> 32);
1051289153Scem		if (rc != 0)
1052289153Scem			goto out;
1053250079Scarl
1054289153Scem		rc = ntb_write_remote_spad(ntb, IF_NTB_MW0_SZ_LOW + (i * 2),
1055289153Scem		    (uint32_t)ntb_get_mw_size(ntb, i));
1056289153Scem		if (rc != 0)
1057289153Scem			goto out;
1058289153Scem	}
1059250079Scarl
1060289208Scem	rc = ntb_write_remote_spad(ntb, IF_NTB_NUM_MWS, num_mw);
1061250079Scarl	if (rc != 0)
1062250079Scarl		goto out;
1063250079Scarl
1064250079Scarl	rc = ntb_write_remote_spad(ntb, IF_NTB_NUM_QPS, nt->max_qps);
1065250079Scarl	if (rc != 0)
1066250079Scarl		goto out;
1067250079Scarl
1068289153Scem	rc = ntb_write_remote_spad(ntb, IF_NTB_VERSION, NTB_TRANSPORT_VERSION);
1069250079Scarl	if (rc != 0)
1070250079Scarl		goto out;
1071250079Scarl
1072250079Scarl	/* Query the remote side for its info */
1073250079Scarl	rc = ntb_read_local_spad(ntb, IF_NTB_VERSION, &val);
1074250079Scarl	if (rc != 0)
1075250079Scarl		goto out;
1076250079Scarl
1077250079Scarl	if (val != NTB_TRANSPORT_VERSION)
1078250079Scarl		goto out;
1079250079Scarl
1080250079Scarl	rc = ntb_read_local_spad(ntb, IF_NTB_NUM_QPS, &val);
1081250079Scarl	if (rc != 0)
1082250079Scarl		goto out;
1083250079Scarl
1084250079Scarl	if (val != nt->max_qps)
1085250079Scarl		goto out;
1086250079Scarl
1087289153Scem	rc = ntb_read_local_spad(ntb, IF_NTB_NUM_MWS, &val);
1088250079Scarl	if (rc != 0)
1089250079Scarl		goto out;
1090250079Scarl
1091289208Scem	if (val != num_mw)
1092250079Scarl		goto out;
1093250079Scarl
1094289208Scem	for (i = 0; i < num_mw; i++) {
1095289153Scem		rc = ntb_read_local_spad(ntb, IF_NTB_MW0_SZ_HIGH + (i * 2),
1096289153Scem		    &val);
1097289153Scem		if (rc != 0)
1098289153Scem			goto free_mws;
1099250079Scarl
1100289153Scem		val64 = (uint64_t)val << 32;
1101250079Scarl
1102289153Scem		rc = ntb_read_local_spad(ntb, IF_NTB_MW0_SZ_LOW + (i * 2),
1103289153Scem		    &val);
1104289153Scem		if (rc != 0)
1105289153Scem			goto free_mws;
1106250079Scarl
1107289153Scem		val64 |= val;
1108250079Scarl
1109289153Scem		rc = ntb_set_mw(nt, i, val64);
1110289153Scem		if (rc != 0)
1111289153Scem			goto free_mws;
1112289153Scem	}
1113289153Scem
1114250079Scarl	nt->transport_link = NTB_LINK_UP;
1115255268Scarl	if (bootverbose)
1116255268Scarl		device_printf(ntb_get_device(ntb), "transport link up\n");
1117250079Scarl
1118250079Scarl	for (i = 0; i < nt->max_qps; i++) {
1119250079Scarl		qp = &nt->qps[i];
1120250079Scarl
1121250079Scarl		ntb_transport_setup_qp_mw(nt, i);
1122250079Scarl
1123250079Scarl		if (qp->client_ready == NTB_LINK_UP)
1124250079Scarl			callout_reset(&qp->link_work, 0, ntb_qp_link_work, qp);
1125250079Scarl	}
1126250079Scarl
1127250079Scarl	return;
1128250079Scarl
1129289153Scemfree_mws:
1130289153Scem	for (i = 0; i < NTB_NUM_MW; i++)
1131289153Scem		ntb_free_mw(nt, i);
1132250079Scarlout:
1133250079Scarl	if (ntb_query_link_status(ntb))
1134250079Scarl		callout_reset(&nt->link_work,
1135289153Scem		    NTB_LINK_DOWN_TIMEOUT * hz / 1000, ntb_transport_link_work, nt);
1136250079Scarl}
1137250079Scarl
1138250079Scarlstatic int
1139250079Scarlntb_set_mw(struct ntb_netdev *nt, int num_mw, unsigned int size)
1140250079Scarl{
1141250079Scarl	struct ntb_transport_mw *mw = &nt->mw[num_mw];
1142250079Scarl
1143289154Scem	/* No need to re-setup */
1144289154Scem	if (mw->size == size)
1145289154Scem		return (0);
1146289154Scem
1147289154Scem	if (mw->size != 0)
1148289154Scem		ntb_free_mw(nt, num_mw);
1149289154Scem
1150250079Scarl	/* Alloc memory for receiving data.  Must be 4k aligned */
1151250079Scarl	mw->size = size;
1152250079Scarl
1153250079Scarl	mw->virt_addr = contigmalloc(mw->size, M_NTB_IF, M_ZERO, 0,
1154250079Scarl	    BUS_SPACE_MAXADDR, mw->size, 0);
1155250079Scarl	if (mw->virt_addr == NULL) {
1156289154Scem		mw->size = 0;
1157250079Scarl		printf("ntb: Unable to allocate MW buffer of size %d\n",
1158250079Scarl		    (int)mw->size);
1159250079Scarl		return (ENOMEM);
1160250079Scarl	}
1161250079Scarl	/* TODO: replace with bus_space_* functions */
1162250079Scarl	mw->dma_addr = vtophys(mw->virt_addr);
1163250079Scarl
1164250079Scarl	/* Notify HW the memory location of the receive buffer */
1165250079Scarl	ntb_set_mw_addr(nt->ntb, num_mw, mw->dma_addr);
1166250079Scarl
1167250079Scarl	return (0);
1168250079Scarl}
1169250079Scarl
1170250079Scarlstatic void
1171289153Scemntb_free_mw(struct ntb_netdev *nt, int num_mw)
1172289153Scem{
1173289153Scem	struct ntb_transport_mw *mw = &nt->mw[num_mw];
1174289153Scem
1175289153Scem	if (mw->virt_addr == NULL)
1176289153Scem		return;
1177289153Scem
1178289153Scem	contigfree(mw->virt_addr, mw->size, M_NTB_IF);
1179289153Scem	mw->virt_addr = NULL;
1180289153Scem}
1181289153Scem
1182289153Scemstatic void
1183250079Scarlntb_transport_setup_qp_mw(struct ntb_netdev *nt, unsigned int qp_num)
1184250079Scarl{
1185250079Scarl	struct ntb_transport_qp *qp = &nt->qps[qp_num];
1186250079Scarl	void *offset;
1187250079Scarl	unsigned int rx_size, num_qps_mw;
1188250079Scarl	uint8_t mw_num = QP_TO_MW(qp_num);
1189250079Scarl	unsigned int i;
1190250079Scarl
1191250079Scarl	if (nt->max_qps % NTB_NUM_MW && mw_num < nt->max_qps % NTB_NUM_MW)
1192250079Scarl		num_qps_mw = nt->max_qps / NTB_NUM_MW + 1;
1193250079Scarl	else
1194250079Scarl		num_qps_mw = nt->max_qps / NTB_NUM_MW;
1195250079Scarl
1196250079Scarl	rx_size = (unsigned int) nt->mw[mw_num].size / num_qps_mw;
1197250079Scarl	qp->remote_rx_info = (void *)((uint8_t *)nt->mw[mw_num].virt_addr +
1198250079Scarl			     (qp_num / NTB_NUM_MW * rx_size));
1199250079Scarl	rx_size -= sizeof(struct ntb_rx_info);
1200250079Scarl
1201289152Scem	qp->rx_buff = qp->remote_rx_info + 1;
1202289156Scem	/* Due to house-keeping, there must be at least 2 buffs */
1203250079Scarl	qp->rx_max_frame = min(transport_mtu + sizeof(struct ntb_payload_header),
1204289156Scem	    rx_size / 2);
1205250079Scarl	qp->rx_max_entry = rx_size / qp->rx_max_frame;
1206250079Scarl	qp->rx_index = 0;
1207250079Scarl
1208289156Scem	qp->remote_rx_info->entry = qp->rx_max_entry - 1;
1209250079Scarl
1210250079Scarl	/* setup the hdr offsets with 0's */
1211250079Scarl	for (i = 0; i < qp->rx_max_entry; i++) {
1212250079Scarl		offset = (void *)((uint8_t *)qp->rx_buff +
1213250079Scarl		    qp->rx_max_frame * (i + 1) -
1214250079Scarl		    sizeof(struct ntb_payload_header));
1215250079Scarl		memset(offset, 0, sizeof(struct ntb_payload_header));
1216250079Scarl	}
1217250079Scarl
1218250079Scarl	qp->rx_pkts = 0;
1219250079Scarl	qp->tx_pkts = 0;
1220289155Scem	qp->tx_index = 0;
1221250079Scarl}
1222250079Scarl
1223250079Scarlstatic void
1224250079Scarlntb_qp_link_work(void *arg)
1225250079Scarl{
1226250079Scarl	struct ntb_transport_qp *qp = arg;
1227250079Scarl	struct ntb_softc *ntb = qp->ntb;
1228250079Scarl	struct ntb_netdev *nt = qp->transport;
1229250079Scarl	int rc, val;
1230250079Scarl
1231250079Scarl
1232250079Scarl	rc = ntb_read_remote_spad(ntb, IF_NTB_QP_LINKS, &val);
1233250079Scarl	if (rc != 0)
1234250079Scarl		return;
1235250079Scarl
1236250079Scarl	rc = ntb_write_remote_spad(ntb, IF_NTB_QP_LINKS, val | 1 << qp->qp_num);
1237250079Scarl
1238250079Scarl	/* query remote spad for qp ready bits */
1239250079Scarl	rc = ntb_read_local_spad(ntb, IF_NTB_QP_LINKS, &val);
1240250079Scarl
1241250079Scarl	/* See if the remote side is up */
1242250079Scarl	if ((1 << qp->qp_num & val) != 0) {
1243250079Scarl		qp->qp_link = NTB_LINK_UP;
1244250079Scarl		if (qp->event_handler != NULL)
1245250079Scarl			qp->event_handler(qp->cb_data, NTB_LINK_UP);
1246255268Scarl		if (bootverbose)
1247255268Scarl			device_printf(ntb_get_device(ntb), "qp link up\n");
1248250079Scarl	} else if (nt->transport_link == NTB_LINK_UP) {
1249250079Scarl		callout_reset(&qp->link_work,
1250250079Scarl		    NTB_LINK_DOWN_TIMEOUT * hz / 1000, ntb_qp_link_work, qp);
1251250079Scarl	}
1252250079Scarl}
1253250079Scarl
1254250079Scarl/* Link down event*/
1255250079Scarlstatic void
1256250079Scarlntb_transport_link_cleanup(struct ntb_netdev *nt)
1257250079Scarl{
1258250079Scarl	int i;
1259250079Scarl
1260289273Scem	/* Pass along the info to any clients */
1261289273Scem	for (i = 0; i < nt->max_qps; i++)
1262289273Scem		if (!test_bit(i, &nt->qp_bitmap))
1263289273Scem			ntb_qp_link_down(&nt->qps[i]);
1264289273Scem
1265250079Scarl	if (nt->transport_link == NTB_LINK_DOWN)
1266250079Scarl		callout_drain(&nt->link_work);
1267250079Scarl	else
1268250079Scarl		nt->transport_link = NTB_LINK_DOWN;
1269250079Scarl
1270250079Scarl	/*
1271250079Scarl	 * The scratchpad registers keep the values if the remote side
1272250079Scarl	 * goes down, blast them now to give them a sane value the next
1273250079Scarl	 * time they are accessed
1274250079Scarl	 */
1275250079Scarl	for (i = 0; i < IF_NTB_MAX_SPAD; i++)
1276250079Scarl		ntb_write_local_spad(nt->ntb, i, 0);
1277250079Scarl}
1278250079Scarl
1279250079Scarl
1280250079Scarlstatic void
1281250079Scarlntb_qp_link_down(struct ntb_transport_qp *qp)
1282250079Scarl{
1283250079Scarl
1284250079Scarl	ntb_qp_link_cleanup(qp);
1285250079Scarl}
1286250079Scarl
1287250079Scarlstatic void
1288250079Scarlntb_qp_link_cleanup(struct ntb_transport_qp *qp)
1289250079Scarl{
1290250079Scarl	struct ntb_netdev *nt = qp->transport;
1291250079Scarl
1292250079Scarl	if (qp->qp_link == NTB_LINK_DOWN) {
1293250079Scarl		callout_drain(&qp->link_work);
1294250079Scarl		return;
1295250079Scarl	}
1296250079Scarl
1297250079Scarl	if (qp->event_handler != NULL)
1298250079Scarl		qp->event_handler(qp->cb_data, NTB_LINK_DOWN);
1299250079Scarl
1300250079Scarl	qp->qp_link = NTB_LINK_DOWN;
1301250079Scarl
1302250079Scarl	if (nt->transport_link == NTB_LINK_UP)
1303250079Scarl		callout_reset(&qp->link_work,
1304250079Scarl		    NTB_LINK_DOWN_TIMEOUT * hz / 1000, ntb_qp_link_work, qp);
1305250079Scarl}
1306250079Scarl
1307250079Scarl/* Link commanded down */
1308250079Scarl/**
1309250079Scarl * ntb_transport_link_down - Notify NTB transport to no longer enqueue data
1310250079Scarl * @qp: NTB transport layer queue to be disabled
1311250079Scarl *
1312250079Scarl * Notify NTB transport layer of client's desire to no longer receive data on
1313250079Scarl * transport queue specified.  It is the client's responsibility to ensure all
1314289266Scem * entries on queue are purged or otherwise handled appropriately.
1315250079Scarl */
1316250079Scarlstatic void
1317250079Scarlntb_transport_link_down(struct ntb_transport_qp *qp)
1318250079Scarl{
1319250079Scarl	int rc, val;
1320250079Scarl
1321250079Scarl	if (qp == NULL)
1322250079Scarl		return;
1323250079Scarl
1324250079Scarl	qp->client_ready = NTB_LINK_DOWN;
1325250079Scarl
1326250079Scarl	rc = ntb_read_remote_spad(qp->ntb, IF_NTB_QP_LINKS, &val);
1327250079Scarl	if (rc != 0)
1328250079Scarl		return;
1329250079Scarl
1330250079Scarl	rc = ntb_write_remote_spad(qp->ntb, IF_NTB_QP_LINKS,
1331250079Scarl	   val & ~(1 << qp->qp_num));
1332250079Scarl
1333250079Scarl	if (qp->qp_link == NTB_LINK_UP)
1334250079Scarl		ntb_send_link_down(qp);
1335250079Scarl	else
1336250079Scarl		callout_drain(&qp->link_work);
1337250079Scarl
1338250079Scarl}
1339250079Scarl
1340250079Scarlstatic void
1341250079Scarlntb_send_link_down(struct ntb_transport_qp *qp)
1342250079Scarl{
1343250079Scarl	struct ntb_queue_entry *entry;
1344250079Scarl	int i, rc;
1345250079Scarl
1346250079Scarl	if (qp->qp_link == NTB_LINK_DOWN)
1347250079Scarl		return;
1348250079Scarl
1349250079Scarl	qp->qp_link = NTB_LINK_DOWN;
1350250079Scarl
1351250079Scarl	for (i = 0; i < NTB_LINK_DOWN_TIMEOUT; i++) {
1352250079Scarl		entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q);
1353250079Scarl		if (entry != NULL)
1354250079Scarl			break;
1355250079Scarl		pause("NTB Wait for link down", hz / 10);
1356250079Scarl	}
1357250079Scarl
1358250079Scarl	if (entry == NULL)
1359250079Scarl		return;
1360250079Scarl
1361250079Scarl	entry->cb_data = NULL;
1362250079Scarl	entry->buf = NULL;
1363250079Scarl	entry->len = 0;
1364250079Scarl	entry->flags = IF_NTB_LINK_DOWN_FLAG;
1365250079Scarl
1366250079Scarl	mtx_lock(&qp->transport->tx_lock);
1367250079Scarl	rc = ntb_process_tx(qp, entry);
1368250079Scarl	if (rc != 0)
1369250079Scarl		printf("ntb: Failed to send link down\n");
1370250079Scarl	mtx_unlock(&qp->transport->tx_lock);
1371250079Scarl}
1372250079Scarl
1373250079Scarl
1374250079Scarl/* List Management */
1375250079Scarl
1376250079Scarlstatic void
1377250079Scarlntb_list_add(struct mtx *lock, struct ntb_queue_entry *entry,
1378250079Scarl    struct ntb_queue_list *list)
1379250079Scarl{
1380250079Scarl
1381250079Scarl	mtx_lock_spin(lock);
1382250079Scarl	STAILQ_INSERT_TAIL(list, entry, entry);
1383250079Scarl	mtx_unlock_spin(lock);
1384250079Scarl}
1385250079Scarl
1386250079Scarlstatic struct ntb_queue_entry *
1387250079Scarlntb_list_rm(struct mtx *lock, struct ntb_queue_list *list)
1388250079Scarl{
1389250079Scarl	struct ntb_queue_entry *entry;
1390250079Scarl
1391250079Scarl	mtx_lock_spin(lock);
1392250079Scarl	if (STAILQ_EMPTY(list)) {
1393250079Scarl		entry = NULL;
1394250079Scarl		goto out;
1395250079Scarl	}
1396250079Scarl	entry = STAILQ_FIRST(list);
1397250079Scarl	STAILQ_REMOVE_HEAD(list, entry);
1398250079Scarlout:
1399250079Scarl	mtx_unlock_spin(lock);
1400250079Scarl
1401250079Scarl	return (entry);
1402250079Scarl}
1403250079Scarl
1404250079Scarl/* Helper functions */
1405250079Scarl/* TODO: This too should really be part of the kernel */
1406250079Scarl#define EUI48_MULTICAST			1 << 0
1407250079Scarl#define EUI48_LOCALLY_ADMINISTERED	1 << 1
1408250079Scarlstatic void
1409250079Scarlcreate_random_local_eui48(u_char *eaddr)
1410250079Scarl{
1411250079Scarl	static uint8_t counter = 0;
1412250079Scarl	uint32_t seed = ticks;
1413250079Scarl
1414250079Scarl	eaddr[0] = EUI48_LOCALLY_ADMINISTERED;
1415250079Scarl	memcpy(&eaddr[1], &seed, sizeof(uint32_t));
1416250079Scarl	eaddr[5] = counter++;
1417250079Scarl}
1418250079Scarl
1419250079Scarl/**
1420250079Scarl * ntb_transport_max_size - Query the max payload size of a qp
1421250079Scarl * @qp: NTB transport layer queue to be queried
1422250079Scarl *
1423250079Scarl * Query the maximum payload size permissible on the given qp
1424250079Scarl *
1425250079Scarl * RETURNS: the max payload size of a qp
1426250079Scarl */
1427250079Scarlstatic unsigned int
1428250079Scarlntb_transport_max_size(struct ntb_transport_qp *qp)
1429250079Scarl{
1430250079Scarl
1431250079Scarl	if (qp == NULL)
1432250079Scarl		return (0);
1433250079Scarl
1434250079Scarl	return (qp->tx_max_frame - sizeof(struct ntb_payload_header));
1435250079Scarl}
1436