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); }
/* 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); }
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); }