示例#1
0
static void pp_pong(struct pp_ctx *pp)
{
	u32 msg_data = -1, spad_data = -1;
	int pidx = 0;

	/* Read pong data */
	spad_data = ntb_spad_read(pp->ntb, 0);
	msg_data = ntb_msg_read(pp->ntb, &pidx, 0);
	ntb_msg_clear_sts(pp->ntb, -1);

	/*
	 * Scratchpad and message data may differ, since message register can't
	 * be rewritten unless status is cleared. Additionally either of them
	 * might be unsupported
	 */
	dev_dbg(&pp->ntb->dev, "Pong spad %#x, msg %#x (port %d)\n",
		spad_data, msg_data, ntb_peer_port_number(pp->ntb, pidx));

	atomic_inc(&pp->count);

	ntb_db_set_mask(pp->ntb, pp->in_db);
	ntb_db_clear(pp->ntb, pp->in_db);

	hrtimer_start(&pp->timer, ms_to_ktime(delay_ms), HRTIMER_MODE_REL);
}
示例#2
0
/**
 * 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);
}
示例#3
0
/* Transport Rx */
static void
ntb_transport_rxc_db(void *arg, int pending __unused)
{
	struct ntb_transport_qp *qp = arg;
	ntb_q_idx_t i;
	int rc;

	/*
	 * Limit the number of packets processed in a single interrupt to
	 * provide fairness to others
	 */
	CTR0(KTR_NTB, "RX: transport_rx");
	mtx_lock(&qp->transport->rx_lock);
	for (i = 0; i < qp->rx_max_entry; i++) {
		rc = ntb_process_rxc(qp);
		if (rc != 0) {
			CTR0(KTR_NTB, "RX: process_rxc failed");
			break;
		}
	}
	mtx_unlock(&qp->transport->rx_lock);

	if (i == qp->rx_max_entry)
		taskqueue_enqueue(taskqueue_swi, &qp->rxc_db_work);
	else if ((ntb_db_read(qp->ntb) & (1ull << qp->qp_num)) != 0) {
		/* If db is set, clear it and read it back to commit clear. */
		ntb_db_clear(qp->ntb, 1ull << qp->qp_num);
		(void)ntb_db_read(qp->ntb);

		/*
		 * An interrupt may have arrived between finishing
		 * ntb_process_rxc and clearing the doorbell bit: there might
		 * be some more work to do.
		 */
		taskqueue_enqueue(taskqueue_swi, &qp->rxc_db_work);
	}
}