コード例 #1
0
ファイル: if_ntb.c プロジェクト: ele7enxxh/dtrace-pf
/**
 * ntb_transport_create_queue - Create a new NTB transport layer queue
 * @rx_handler: receive callback function
 * @tx_handler: transmit callback function
 * @event_handler: event callback function
 *
 * Create a new NTB transport layer queue and provide the queue with a callback
 * routine for both transmit and receive.  The receive callback routine will be
 * used to pass up data when the transport has received it on the queue.   The
 * transmit callback routine will be called when the transport has completed the
 * transmission of the data on the queue and the data is ready to be freed.
 *
 * RETURNS: pointer to newly created ntb_queue, NULL on error.
 */
static struct ntb_transport_qp *
ntb_transport_create_queue(void *data, struct ntb_softc *pdev,
    const struct ntb_queue_handlers *handlers)
{
	struct ntb_queue_entry *entry;
	struct ntb_transport_qp *qp;
	struct ntb_netdev *nt;
	unsigned int free_queue;
	int rc, i;

	nt = ntb_find_transport(pdev);
	if (nt == NULL)
		goto err;

	free_queue = ffs(nt->qp_bitmap);
	if (free_queue == 0)
		goto err;

	/* decrement free_queue to make it zero based */
	free_queue--;

	clear_bit(free_queue, &nt->qp_bitmap);

	qp = &nt->qps[free_queue];
	qp->cb_data = data;
	qp->rx_handler = handlers->rx_handler;
	qp->tx_handler = handlers->tx_handler;
	qp->event_handler = handlers->event_handler;

	for (i = 0; i < NTB_QP_DEF_NUM_ENTRIES; i++) {
		entry = malloc(sizeof(struct ntb_queue_entry), M_NTB_IF,
		    M_WAITOK|M_ZERO);
		entry->cb_data = nt->ifp;
		entry->buf = NULL;
		entry->len = transport_mtu;
		ntb_list_add(&qp->ntb_rx_pend_q_lock, entry, &qp->rx_pend_q);
	}

	for (i = 0; i < NTB_QP_DEF_NUM_ENTRIES; i++) {
		entry = malloc(sizeof(struct ntb_queue_entry), M_NTB_IF,
		    M_WAITOK|M_ZERO);
		ntb_list_add(&qp->ntb_tx_free_q_lock, entry, &qp->tx_free_q);
	}

	rc = ntb_register_db_callback(qp->ntb, free_queue, qp,
				      ntb_transport_rxc_db);
	if (rc != 0)
		goto err1;

	return (qp);

err1:
	while ((entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q)))
		free(entry, M_NTB_IF);
	while ((entry = ntb_list_rm(&qp->ntb_rx_free_q_lock, &qp->rx_free_q)))
		free(entry, M_NTB_IF);
	set_bit(free_queue, &nt->qp_bitmap);
err:
	return (NULL);
}
コード例 #2
0
ファイル: if_ntb.c プロジェクト: ele7enxxh/dtrace-pf
static void
ntb_rx_completion_task(void *arg, int pending)
{
	struct ntb_transport_qp *qp = arg;
	struct mbuf *m;
	struct ntb_queue_entry *entry;

	CTR0(KTR_NTB, "RX: rx_completion_task");

	while ((entry = ntb_list_rm(&qp->ntb_rx_free_q_lock, &qp->rx_free_q))) {
		m = entry->buf;
		CTR2(KTR_NTB, "RX: completing entry %p, mbuf %p", entry, m);
		if (qp->rx_handler && qp->client_ready == NTB_LINK_UP)
			qp->rx_handler(qp, qp->cb_data, m, entry->len);

		entry->buf = NULL;
		entry->len = qp->transport->bufsize;

		CTR1(KTR_NTB,"RX: entry %p removed from rx_free_q "
		    "and added to rx_pend_q", entry);
		ntb_list_add(&qp->ntb_rx_pend_q_lock, entry, &qp->rx_pend_q);
		if (qp->rx_err_no_buf > qp->last_rx_no_buf) {
			qp->last_rx_no_buf = qp->rx_err_no_buf;
			CTR0(KTR_NTB, "RX: could spawn rx task");
			callout_reset(&qp->rx_full, hz / 1000, ntb_rx_pendq_full,
			    qp);
		}
	}
}
コード例 #3
0
ファイル: if_ntb.c プロジェクト: ele7enxxh/dtrace-pf
/**
 * ntb_transport_tx_enqueue - Enqueue a new NTB queue entry
 * @qp: NTB transport layer queue the entry is to be enqueued on
 * @cb: per buffer pointer for callback function to use
 * @data: pointer to data buffer that will be sent
 * @len: length of the data buffer
 *
 * Enqueue a new transmit buffer onto the transport queue from which a NTB
 * payload will be transmitted.  This assumes that a lock is behing held to
 * serialize access to the qp.
 *
 * RETURNS: An appropriate ERRNO error value on error, or zero for success.
 */
static int
ntb_transport_tx_enqueue(struct ntb_transport_qp *qp, void *cb, void *data,
    unsigned int len)
{
	struct ntb_queue_entry *entry;
	int rc;

	if (qp == NULL || qp->qp_link != NTB_LINK_UP || len == 0) {
		CTR0(KTR_NTB, "TX: link not up");
		return (EINVAL);
	}

	entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q);
	if (entry == NULL) {
		CTR0(KTR_NTB, "TX: could not get entry from tx_free_q");
		return (ENOMEM);
	}
	CTR1(KTR_NTB, "TX: got entry %p from tx_free_q", entry);

	entry->cb_data = cb;
	entry->buf = data;
	entry->len = len;
	entry->flags = 0;

	rc = ntb_process_tx(qp, entry);
	if (rc != 0) {
		ntb_list_add(&qp->ntb_tx_free_q_lock, entry, &qp->tx_free_q);
		CTR1(KTR_NTB,
		    "TX: process_tx failed. Returning entry %p to tx_free_q",
		    entry);
	}
	return (rc);
}
コード例 #4
0
ファイル: if_ntb.c プロジェクト: Digital-Chaos/freebsd
/**
 * ntb_transport_create_queue - Create a new NTB transport layer queue
 * @rx_handler: receive callback function
 * @tx_handler: transmit callback function
 * @event_handler: event callback function
 *
 * Create a new NTB transport layer queue and provide the queue with a callback
 * routine for both transmit and receive.  The receive callback routine will be
 * used to pass up data when the transport has received it on the queue.   The
 * transmit callback routine will be called when the transport has completed the
 * transmission of the data on the queue and the data is ready to be freed.
 *
 * RETURNS: pointer to newly created ntb_queue, NULL on error.
 */
static struct ntb_transport_qp *
ntb_transport_create_queue(void *data, struct ntb_softc *ntb,
    const struct ntb_queue_handlers *handlers)
{
	struct ntb_queue_entry *entry;
	struct ntb_transport_qp *qp;
	struct ntb_transport_ctx *nt;
	unsigned int free_queue;
	int i;

	nt = ntb_get_ctx(ntb, NULL);
	KASSERT(nt != NULL, ("bogus"));

	free_queue = ffs_bit(&nt->qp_bitmap);
	if (free_queue == 0)
		return (NULL);

	/* decrement free_queue to make it zero based */
	free_queue--;

	qp = &nt->qp_vec[free_queue];
	clear_bit(qp->qp_num, &nt->qp_bitmap_free);
	qp->cb_data = data;
	qp->rx_handler = handlers->rx_handler;
	qp->tx_handler = handlers->tx_handler;
	qp->event_handler = handlers->event_handler;

	for (i = 0; i < NTB_QP_DEF_NUM_ENTRIES; i++) {
		entry = malloc(sizeof(*entry), M_NTB_IF, M_WAITOK | M_ZERO);
		entry->cb_data = nt->ifp;
		entry->buf = NULL;
		entry->len = transport_mtu;
		ntb_list_add(&qp->ntb_rx_q_lock, entry, &qp->rx_pend_q);
	}

	for (i = 0; i < NTB_QP_DEF_NUM_ENTRIES; i++) {
		entry = malloc(sizeof(*entry), M_NTB_IF, M_WAITOK | M_ZERO);
		ntb_list_add(&qp->ntb_tx_free_q_lock, entry, &qp->tx_free_q);
	}

	ntb_db_clear(ntb, 1ull << qp->qp_num);
	ntb_db_clear_mask(ntb, 1ull << qp->qp_num);
	return (qp);
}
コード例 #5
0
ファイル: if_ntb.c プロジェクト: Digital-Chaos/freebsd
static void
ntb_memcpy_tx(struct ntb_transport_qp *qp, struct ntb_queue_entry *entry,
    void *offset)
{
	struct ntb_payload_header *hdr;

	/* This piece is from Linux' ntb_async_tx() */
	hdr = (struct ntb_payload_header *)((char *)offset + qp->tx_max_frame -
	    sizeof(struct ntb_payload_header));
	entry->x_hdr = hdr;
	iowrite32(entry->len, &hdr->len);
	iowrite32(qp->tx_pkts, &hdr->ver);

	/* This piece is ntb_memcpy_tx() */
	CTR2(KTR_NTB, "TX: copying %d bytes to offset %p", entry->len, offset);
	if (entry->buf != NULL) {
		m_copydata((struct mbuf *)entry->buf, 0, entry->len, offset);

		/*
		 * Ensure that the data is fully copied before setting the
		 * flags
		 */
		wmb();
	}

	/* The rest is ntb_tx_copy_callback() */
	iowrite32(entry->flags | IF_NTB_DESC_DONE_FLAG, &hdr->flags);
	CTR1(KTR_NTB, "TX: hdr %p set DESC_DONE", hdr);

	ntb_peer_db_set(qp->ntb, 1ull << qp->qp_num);

	/*
	 * The entry length can only be zero if the packet is intended to be a
	 * "link down" or similar.  Since no payload is being sent in these
	 * cases, there is nothing to add to the completion queue.
	 */
	if (entry->len > 0) {
		qp->tx_bytes += entry->len;

		if (qp->tx_handler)
			qp->tx_handler(qp, qp->cb_data, entry->buf,
			    entry->len);
		else
			m_freem(entry->buf);
		entry->buf = NULL;
	}

	CTR3(KTR_NTB,
	    "TX: entry %p sent. hdr->ver = %u, hdr->flags = 0x%x, Returning "
	    "to tx_free_q", entry, hdr->ver, hdr->flags);
	ntb_list_add(&qp->ntb_tx_free_q_lock, entry, &qp->tx_free_q);
}
コード例 #6
0
ファイル: if_ntb.c プロジェクト: ele7enxxh/dtrace-pf
static void
ntb_rx_copy_task(struct ntb_transport_qp *qp, struct ntb_queue_entry *entry,
    void *offset)
{
	struct ifnet *ifp = entry->cb_data;
	unsigned int len = entry->len;
	struct mbuf *m;

	CTR2(KTR_NTB, "RX: copying %d bytes from offset %p", len, offset);
	m = m_devget(offset, len, 0, ifp, NULL);
	m->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID;

	entry->buf = (void *)m;

	CTR2(KTR_NTB,
	    "RX: copied entry %p to mbuf %p. Adding entry to rx_free_q", entry,
	    m);
	ntb_list_add(&qp->ntb_rx_free_q_lock, entry, &qp->rx_free_q);

	taskqueue_enqueue(taskqueue_swi, &qp->rx_completion_task);
}
コード例 #7
0
ファイル: if_ntb.c プロジェクト: Digital-Chaos/freebsd
static int
ntb_process_tx(struct ntb_transport_qp *qp, struct ntb_queue_entry *entry)
{
	void *offset;

	offset = qp->tx_mw + qp->tx_max_frame * qp->tx_index;
	CTR3(KTR_NTB,
	    "TX: process_tx: tx_pkts=%lu, tx_index=%u, remote entry=%u",
	    qp->tx_pkts, qp->tx_index, qp->remote_rx_info->entry);
	if (qp->tx_index == qp->remote_rx_info->entry) {
		CTR0(KTR_NTB, "TX: ring full");
		qp->tx_ring_full++;
		return (EAGAIN);
	}

	if (entry->len > qp->tx_max_frame - sizeof(struct ntb_payload_header)) {
		if (qp->tx_handler != NULL)
			qp->tx_handler(qp, qp->cb_data, entry->buf,
			    EIO);
		else
			m_freem(entry->buf);

		entry->buf = NULL;
		ntb_list_add(&qp->ntb_tx_free_q_lock, entry, &qp->tx_free_q);
		CTR1(KTR_NTB,
		    "TX: frame too big. returning entry %p to tx_free_q",
		    entry);
		return (0);
	}
	CTR2(KTR_NTB, "TX: copying entry %p to offset %p", entry, offset);
	ntb_memcpy_tx(qp, entry, offset);

	qp->tx_index++;
	qp->tx_index %= qp->tx_max_entry;

	qp->tx_pkts++;

	return (0);
}
コード例 #8
0
ファイル: if_ntb.c プロジェクト: ele7enxxh/dtrace-pf
static void
ntb_tx_copy_task(struct ntb_transport_qp *qp, struct ntb_queue_entry *entry,
    void *offset)
{
	struct ntb_payload_header *hdr;

	CTR2(KTR_NTB, "TX: copying %d bytes to offset %p", entry->len, offset);
	if (entry->buf != NULL)
		m_copydata((struct mbuf *)entry->buf, 0, entry->len, offset);

	hdr = (struct ntb_payload_header *)((char *)offset + qp->tx_max_frame -
	    sizeof(struct ntb_payload_header));
	hdr->len = entry->len; /* TODO: replace with bus_space_write */
	hdr->ver = qp->tx_pkts; /* TODO: replace with bus_space_write */
	wmb();
	/* TODO: replace with bus_space_write */
	hdr->flags = entry->flags | IF_NTB_DESC_DONE_FLAG;

	ntb_ring_sdb(qp->ntb, qp->qp_num);

	/* 
	 * The entry length can only be zero if the packet is intended to be a
	 * "link down" or similar.  Since no payload is being sent in these
	 * cases, there is nothing to add to the completion queue.
	 */
	if (entry->len > 0) {
		qp->tx_bytes += entry->len;

		if (qp->tx_handler)
			qp->tx_handler(qp, qp->cb_data, entry->cb_data,
				       entry->len);
	}

	CTR2(KTR_NTB,
	    "TX: entry %p sent. hdr->ver = %d, Returning to tx_free_q", entry,
	    hdr->ver);
	ntb_list_add(&qp->ntb_tx_free_q_lock, entry, &qp->tx_free_q);
}
コード例 #9
0
ファイル: if_ntb.c プロジェクト: ele7enxxh/dtrace-pf
static int
ntb_process_rxc(struct ntb_transport_qp *qp)
{
	struct ntb_payload_header *hdr;
	struct ntb_queue_entry *entry;
	void *offset;

	offset = (void *)
	    ((char *)qp->rx_buff + qp->rx_max_frame * qp->rx_index);
	hdr = (void *)
	    ((char *)offset + qp->rx_max_frame -
		sizeof(struct ntb_payload_header));

	CTR1(KTR_NTB, "RX: process_rxc rx_index = %u", qp->rx_index);
	entry = ntb_list_rm(&qp->ntb_rx_pend_q_lock, &qp->rx_pend_q);
	if (entry == NULL) {
		qp->rx_err_no_buf++;
		CTR0(KTR_NTB, "RX: No entries in rx_pend_q");
		return (ENOMEM);
	}
	callout_stop(&qp->rx_full);
	CTR1(KTR_NTB, "RX: rx entry %p from rx_pend_q", entry);

	if ((hdr->flags & IF_NTB_DESC_DONE_FLAG) == 0) {
		CTR1(KTR_NTB,
		    "RX: hdr not done. Returning entry %p to rx_pend_q", entry);
		ntb_list_add(&qp->ntb_rx_pend_q_lock, entry, &qp->rx_pend_q);
		qp->rx_ring_empty++;
		return (EAGAIN);
	}

	if (hdr->ver != (uint32_t) qp->rx_pkts) {
		CTR3(KTR_NTB,"RX: ver != rx_pkts (%x != %lx). "
		    "Returning entry %p to rx_pend_q", hdr->ver, qp->rx_pkts,
		    entry);
		ntb_list_add(&qp->ntb_rx_pend_q_lock, entry, &qp->rx_pend_q);
		qp->rx_err_ver++;
		return (EIO);
	}

	if ((hdr->flags & IF_NTB_LINK_DOWN_FLAG) != 0) {
		ntb_qp_link_down(qp);
		CTR1(KTR_NTB,
		    "RX: link down. adding entry %p back to rx_pend_q", entry);
		ntb_list_add(&qp->ntb_rx_pend_q_lock, entry, &qp->rx_pend_q);
		goto out;
	}

	if (hdr->len <= entry->len) {
		entry->len = hdr->len;
		ntb_rx_copy_task(qp, entry, offset);
	} else {
		CTR1(KTR_NTB,
		    "RX: len too long. Returning entry %p to rx_pend_q", entry);
		ntb_list_add(&qp->ntb_rx_pend_q_lock, entry, &qp->rx_pend_q);

		qp->rx_err_oflow++;
	}

	qp->rx_bytes += hdr->len;
	qp->rx_pkts++;
	CTR1(KTR_NTB, "RX: received %ld rx_pkts", qp->rx_pkts);


out:
	/* Ensure that the data is globally visible before clearing the flag */
	wmb();
	hdr->flags = 0;
	/* TODO: replace with bus_space_write */
	qp->rx_info->entry = qp->rx_index;

	qp->rx_index++;
	qp->rx_index %= qp->rx_max_entry;

	return (0);
}