Esempio n. 1
0
static void
ntb_transport_init_queue(struct ntb_netdev *nt, unsigned int qp_num)
{
	struct ntb_transport_qp *qp;
	unsigned int num_qps_mw, tx_size;
	uint8_t mw_num = QP_TO_MW(qp_num);

	qp = &nt->qps[qp_num];
	qp->qp_num = qp_num;
	qp->transport = nt;
	qp->ntb = nt->ntb;
	qp->qp_link = NTB_LINK_DOWN;
	qp->client_ready = NTB_LINK_DOWN;
	qp->event_handler = NULL;

	if (nt->max_qps % NTB_NUM_MW && mw_num < nt->max_qps % NTB_NUM_MW)
		num_qps_mw = nt->max_qps / NTB_NUM_MW + 1;
	else
		num_qps_mw = nt->max_qps / NTB_NUM_MW;

	tx_size = (unsigned int) ntb_get_mw_size(qp->ntb, mw_num) / num_qps_mw;
	qp->rx_info = (struct ntb_rx_info *)
	    ((char *)ntb_get_mw_vbase(qp->ntb, mw_num) +
	    (qp_num / NTB_NUM_MW * tx_size));
	tx_size -= sizeof(struct ntb_rx_info);

	qp->tx_mw = qp->rx_info + sizeof(struct ntb_rx_info);
	qp->tx_max_frame = min(transport_mtu + sizeof(struct ntb_payload_header),
	    tx_size);
	qp->tx_max_entry = tx_size / qp->tx_max_frame;
	qp->tx_index = 0;

	callout_init(&qp->link_work, 0);
	callout_init(&qp->queue_full, CALLOUT_MPSAFE);
	callout_init(&qp->rx_full, CALLOUT_MPSAFE);

	mtx_init(&qp->ntb_rx_pend_q_lock, "ntb rx pend q", NULL, MTX_SPIN);
	mtx_init(&qp->ntb_rx_free_q_lock, "ntb rx free q", NULL, MTX_SPIN);
	mtx_init(&qp->ntb_tx_free_q_lock, "ntb tx free q", NULL, MTX_SPIN);
	TASK_INIT(&qp->rx_completion_task, 0, ntb_rx_completion_task, qp);

	STAILQ_INIT(&qp->rx_pend_q);
	STAILQ_INIT(&qp->rx_free_q);
	STAILQ_INIT(&qp->tx_free_q);
}
Esempio n. 2
0
/* Link bring up */
static void
ntb_transport_link_work(void *arg)
{
	struct ntb_netdev *nt = arg;
	struct ntb_softc *ntb = nt->ntb;
	struct ntb_transport_qp *qp;
	uint32_t val;
	int rc, i;

	/* send the local info */
	rc = ntb_write_remote_spad(ntb, IF_NTB_VERSION, NTB_TRANSPORT_VERSION);
	if (rc != 0)
		goto out;

	rc = ntb_write_remote_spad(ntb, IF_NTB_MW0_SZ, ntb_get_mw_size(ntb, 0));
	if (rc != 0)
		goto out;

	rc = ntb_write_remote_spad(ntb, IF_NTB_MW1_SZ, ntb_get_mw_size(ntb, 1));
	if (rc != 0)
		goto out;

	rc = ntb_write_remote_spad(ntb, IF_NTB_NUM_QPS, nt->max_qps);
	if (rc != 0)
		goto out;

	rc = ntb_read_remote_spad(ntb, IF_NTB_QP_LINKS, &val);
	if (rc != 0)
		goto out;

	rc = ntb_write_remote_spad(ntb, IF_NTB_QP_LINKS, val);
	if (rc != 0)
		goto out;

	/* Query the remote side for its info */
	rc = ntb_read_local_spad(ntb, IF_NTB_VERSION, &val);
	if (rc != 0)
		goto out;

	if (val != NTB_TRANSPORT_VERSION)
		goto out;

	rc = ntb_read_local_spad(ntb, IF_NTB_NUM_QPS, &val);
	if (rc != 0)
		goto out;

	if (val != nt->max_qps)
		goto out;

	rc = ntb_read_local_spad(ntb, IF_NTB_MW0_SZ, &val);
	if (rc != 0)
		goto out;

	if (val == 0)
		goto out;

	rc = ntb_set_mw(nt, 0, val);
	if (rc != 0)
		return;

	rc = ntb_read_local_spad(ntb, IF_NTB_MW1_SZ, &val);
	if (rc != 0)
		goto out;

	if (val == 0)
		goto out;

	rc = ntb_set_mw(nt, 1, val);
	if (rc != 0)
		return;

	nt->transport_link = NTB_LINK_UP;
	if (bootverbose)
		device_printf(ntb_get_device(ntb), "transport link up\n");

	for (i = 0; i < nt->max_qps; i++) {
		qp = &nt->qps[i];

		ntb_transport_setup_qp_mw(nt, i);

		if (qp->client_ready == NTB_LINK_UP)
			callout_reset(&qp->link_work, 0, ntb_qp_link_work, qp);
	}

	return;

out:
	if (ntb_query_link_status(ntb))
		callout_reset(&nt->link_work,
				      NTB_LINK_DOWN_TIMEOUT * hz / 1000, ntb_transport_link_work, nt);
}
Esempio n. 3
0
static int
ntb_setup_xeon(struct ntb_softc *ntb)
{

	ntb->reg_ofs.ldb	= XEON_PDOORBELL_OFFSET;
	ntb->reg_ofs.ldb_mask	= XEON_PDBMSK_OFFSET;
	ntb->reg_ofs.spad_local	= XEON_SPAD_OFFSET;
	ntb->reg_ofs.bar2_xlat	= XEON_SBAR2XLAT_OFFSET;
	ntb->reg_ofs.bar4_xlat	= XEON_SBAR4XLAT_OFFSET;
	if (HAS_FEATURE(NTB_SPLIT_BAR))
		ntb->reg_ofs.bar5_xlat = XEON_SBAR5XLAT_OFFSET;

	switch (ntb->conn_type) {
	case NTB_CONN_B2B:
		/*
		 * reg_ofs.rdb and reg_ofs.spad_remote are effectively ignored
		 * with the NTB_REGS_THRU_MW errata mode enabled.  (See
		 * ntb_ring_doorbell() and ntb_read/write_remote_spad().)
		 */
		ntb->reg_ofs.rdb	 = XEON_B2B_DOORBELL_OFFSET;
		ntb->reg_ofs.spad_remote = XEON_B2B_SPAD_OFFSET;

		ntb->limits.max_spads	 = XEON_MAX_SPADS;
		break;

	case NTB_CONN_RP:
		/*
		 * Every Xeon today needs NTB_REGS_THRU_MW, so punt on RP for
		 * now.
		 */
		KASSERT(HAS_FEATURE(NTB_REGS_THRU_MW),
		    ("Xeon without MW errata unimplemented"));
		device_printf(ntb->device,
		    "NTB-RP disabled to due hardware errata.\n");
		return (ENXIO);

	case NTB_CONN_TRANSPARENT:
	default:
		device_printf(ntb->device, "Connection type %d not supported\n",
		    ntb->conn_type);
		return (ENXIO);
	}

	/*
	 * There is a Xeon hardware errata related to writes to SDOORBELL or
	 * B2BDOORBELL in conjunction with inbound access to NTB MMIO space,
	 * which may hang the system.  To workaround this use the second memory
	 * window to access the interrupt and scratch pad registers on the
	 * remote system.
	 *
	 * There is another HW errata on the limit registers -- they can only
	 * be written when the base register is (?)4GB aligned and < 32-bit.
	 * This should already be the case based on the driver defaults, but
	 * write the limit registers first just in case.
	 */
	if (HAS_FEATURE(NTB_REGS_THRU_MW)) {
		/*
		 * Set the Limit register to 4k, the minimum size, to prevent
		 * an illegal access.
		 *
		 * XXX: Should this be PBAR5LMT / get_mw_size(, max_mw - 1)?
		 */
		ntb_reg_write(8, XEON_PBAR4LMT_OFFSET,
		    ntb_get_mw_size(ntb, 1) + 0x1000);
		/* Reserve the last MW for mapping remote spad */
		ntb->limits.max_mw--;
	} else
		/*
		 * Disable the limit register, just in case it is set to
		 * something silly.  A 64-bit write will also clear PBAR5LMT in
		 * split-bar mode, and this is desired.
		 */
		ntb_reg_write(8, XEON_PBAR4LMT_OFFSET, 0);

	ntb->reg_ofs.lnk_cntl	 = XEON_NTBCNTL_OFFSET;
	ntb->reg_ofs.lnk_stat	 = XEON_LINK_STATUS_OFFSET;
	ntb->reg_ofs.spci_cmd	 = XEON_PCICMD_OFFSET;

	ntb->limits.max_db_bits	 = XEON_MAX_DB_BITS;
	ntb->limits.msix_cnt	 = XEON_MSIX_CNT;
	ntb->bits_per_vector	 = XEON_DB_BITS_PER_VEC;

	/*
	 * HW Errata on bit 14 of b2bdoorbell register.  Writes will not be
	 * mirrored to the remote system.  Shrink the number of bits by one,
	 * since bit 14 is the last bit.
	 *
	 * On REGS_THRU_MW errata mode, we don't use the b2bdoorbell register
	 * anyway.  Nor for non-B2B connection types.
	 */
	if (HAS_FEATURE(NTB_B2BDOORBELL_BIT14) &&
	    !HAS_FEATURE(NTB_REGS_THRU_MW) &&
	    ntb->conn_type == NTB_CONN_B2B)
		ntb->limits.max_db_bits = XEON_MAX_DB_BITS - 1;

	configure_xeon_secondary_side_bars(ntb);

	/* Enable Bus Master and Memory Space on the secondary side */
	if (ntb->conn_type == NTB_CONN_B2B)
		ntb_reg_write(2, ntb->reg_ofs.spci_cmd,
		    PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN);

	/* Enable link training */
	ntb_hw_link_up(ntb);

	return (0);
}