Esempio n. 1
0
static int
ntb_setup_xeon(struct ntb_softc *ntb)
{
	uint8_t val, connection_type;

	val = pci_read_config(ntb->device, NTB_PPD_OFFSET, 1);

	connection_type = val & XEON_PPD_CONN_TYPE;
	switch (connection_type) {
	case NTB_CONN_B2B:
		ntb->conn_type = NTB_CONN_B2B;
		break;
	case NTB_CONN_CLASSIC:
	case NTB_CONN_RP:
	default:
		device_printf(ntb->device, "Connection type %d not supported\n",
		    connection_type);
		return (ENXIO);
	}

	if ((val & XEON_PPD_DEV_TYPE) != 0)
		ntb->dev_type = NTB_DEV_DSD;
	else
		ntb->dev_type = NTB_DEV_USD;

	ntb->reg_ofs.pdb	= XEON_PDOORBELL_OFFSET;
	ntb->reg_ofs.pdb_mask	= XEON_PDBMSK_OFFSET;
	ntb->reg_ofs.sbar2_xlat = XEON_SBAR2XLAT_OFFSET;
	ntb->reg_ofs.sbar4_xlat = XEON_SBAR4XLAT_OFFSET;
	ntb->reg_ofs.lnk_cntl	= XEON_NTBCNTL_OFFSET;
	ntb->reg_ofs.lnk_stat	= XEON_LINK_STATUS_OFFSET;
	ntb->reg_ofs.spad_local	= XEON_SPAD_OFFSET;
	ntb->reg_ofs.spci_cmd	= XEON_PCICMD_OFFSET;

	if (ntb->conn_type == NTB_CONN_B2B) {
		ntb->reg_ofs.sdb	 = XEON_B2B_DOORBELL_OFFSET;
		ntb->reg_ofs.spad_remote = XEON_B2B_SPAD_OFFSET;
		ntb->limits.max_spads	 = XEON_MAX_SPADS;
	} else {
		ntb->reg_ofs.sdb	 = XEON_SDOORBELL_OFFSET;
		ntb->reg_ofs.spad_remote = XEON_SPAD_OFFSET;
		ntb->limits.max_spads	 = XEON_MAX_COMPAT_SPADS;
	}

	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;

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

	/* Enable link training */
	ntb_reg_write(4, ntb->reg_ofs.lnk_cntl,
	    NTB_CNTL_BAR23_SNOOP | NTB_CNTL_BAR45_SNOOP);

	return (0);
}
Esempio n. 2
0
static void
db_iowrite(struct ntb_softc *ntb, uint32_t regoff, uint64_t val)
{

	if (ntb->type == NTB_SOC) {
		ntb_reg_write(8, regoff, val);
		return;
	}

	KASSERT(ntb->type == NTB_XEON, ("bad ntb type"));
	ntb_reg_write(2, regoff, (uint16_t)val);
}
Esempio n. 3
0
static void
configure_xeon_secondary_side_bars(struct ntb_softc *ntb)
{

	if (ntb->dev_type == NTB_DEV_USD) {
		ntb_reg_write(8, XEON_PBAR2XLAT_OFFSET, PBAR2XLAT_USD_ADDR);
		if (HAS_FEATURE(NTB_REGS_THRU_MW))
			ntb_reg_write(8, XEON_PBAR4XLAT_OFFSET,
			    MBAR01_DSD_ADDR);
		else {
			ntb_reg_write(8, XEON_PBAR4XLAT_OFFSET,
			    PBAR4XLAT_USD_ADDR);
			/*
			 * B2B_XLAT_OFFSET is a 64-bit register but can only be
			 * written 32 bits at a time.
			 */
			ntb_reg_write(4, XEON_B2B_XLAT_OFFSETL,
			    MBAR01_DSD_ADDR & 0xffffffff);
			ntb_reg_write(4, XEON_B2B_XLAT_OFFSETU,
			    MBAR01_DSD_ADDR >> 32);
		}
		ntb_reg_write(8, XEON_SBAR0BASE_OFFSET, MBAR01_USD_ADDR);
		ntb_reg_write(8, XEON_SBAR2BASE_OFFSET, MBAR23_USD_ADDR);
		ntb_reg_write(8, XEON_SBAR4BASE_OFFSET, MBAR45_USD_ADDR);
	} else {
Esempio n. 4
0
static void
handle_soc_irq(void *arg)
{
	struct ntb_db_cb *db_cb = arg;
	struct ntb_softc *ntb = db_cb->ntb;

	ntb_reg_write(8, ntb->reg_ofs.pdb, (uint64_t) 1 << db_cb->db_num);

	if (db_cb->callback != NULL)
		db_cb->callback(db_cb->data, db_cb->db_num);
}
Esempio n. 5
0
/* Since we do not have a HW doorbell in SOC, this is only used in JF/JT */
static void
handle_xeon_event_irq(void *arg)
{
	struct ntb_softc *ntb = arg;
	int rc;

	rc = ntb_check_link_status(ntb);
	if (rc != 0)
		device_printf(ntb->device, "Error determining link status\n");

	/* bit 15 is always the link bit */
	ntb_reg_write(2, ntb->reg_ofs.pdb, 1 << ntb->limits.max_db_bits);
}
Esempio n. 6
0
static void
configure_soc_secondary_side_bars(struct ntb_softc *ntb)
{

	if (ntb->dev_type == NTB_DEV_USD) {
		ntb_reg_write(8, SOC_PBAR2XLAT_OFFSET, MBAR23_DSD_ADDR);
		ntb_reg_write(8, SOC_PBAR4XLAT_OFFSET, MBAR4_DSD_ADDR);
		ntb_reg_write(8, SOC_MBAR23_OFFSET, MBAR23_USD_ADDR);
		ntb_reg_write(8, SOC_MBAR45_OFFSET, MBAR4_USD_ADDR);
	} else {
		ntb_reg_write(8, SOC_PBAR2XLAT_OFFSET, MBAR23_USD_ADDR);
		ntb_reg_write(8, SOC_PBAR4XLAT_OFFSET, MBAR4_USD_ADDR);
		ntb_reg_write(8, SOC_MBAR23_OFFSET, MBAR23_DSD_ADDR);
		ntb_reg_write(8, SOC_MBAR45_OFFSET, MBAR4_DSD_ADDR);
	}
}
Esempio n. 7
0
static void
soc_perform_link_restart(struct ntb_softc *ntb)
{
	uint32_t status;

	/* Driver resets the NTB ModPhy lanes - magic! */
	ntb_reg_write(1, SOC_MODPHY_PCSREG6, 0xe0);
	ntb_reg_write(1, SOC_MODPHY_PCSREG4, 0x40);
	ntb_reg_write(1, SOC_MODPHY_PCSREG4, 0x60);
	ntb_reg_write(1, SOC_MODPHY_PCSREG6, 0x60);

	/* Driver waits 100ms to allow the NTB ModPhy to settle */
	pause("ModPhy", hz / 10);

	/* Clear AER Errors, write to clear */
	status = ntb_reg_read(4, SOC_ERRCORSTS_OFFSET);
	status &= PCIM_AER_COR_REPLAY_ROLLOVER;
	ntb_reg_write(4, SOC_ERRCORSTS_OFFSET, status);

	/* Clear unexpected electrical idle event in LTSSM, write to clear */
	status = ntb_reg_read(4, SOC_LTSSMERRSTS0_OFFSET);
	status |= SOC_LTSSMERRSTS0_UNEXPECTEDEI;
	ntb_reg_write(4, SOC_LTSSMERRSTS0_OFFSET, status);

	/* Clear DeSkew Buffer error, write to clear */
	status = ntb_reg_read(4, SOC_DESKEWSTS_OFFSET);
	status |= SOC_DESKEWSTS_DBERR;
	ntb_reg_write(4, SOC_DESKEWSTS_OFFSET, status);

	status = ntb_reg_read(4, SOC_IBSTERRRCRVSTS0_OFFSET);
	status &= SOC_IBIST_ERR_OFLOW;
	ntb_reg_write(4, SOC_IBSTERRRCRVSTS0_OFFSET, status);

	/* Releases the NTB state machine to allow the link to retrain */
	status = ntb_reg_read(4, SOC_LTSSMSTATEJMP_OFFSET);
	status &= ~SOC_LTSSMSTATEJMP_FORCEDETECT;
	ntb_reg_write(4, SOC_LTSSMSTATEJMP_OFFSET, status);
}
Esempio n. 8
0
static int
ntb_setup_soc(struct ntb_softc *ntb)
{

	KASSERT(ntb->conn_type == NTB_CONN_B2B,
	    ("Unsupported NTB configuration (%d)\n", ntb->conn_type));

	/* Initiate PCI-E link training */
	pci_write_config(ntb->device, NTB_PPD_OFFSET,
	    ntb->ppd | SOC_PPD_INIT_LINK, 4);

	ntb->reg_ofs.ldb	 = SOC_PDOORBELL_OFFSET;
	ntb->reg_ofs.ldb_mask	 = SOC_PDBMSK_OFFSET;
	ntb->reg_ofs.rdb	 = SOC_B2B_DOORBELL_OFFSET;
	ntb->reg_ofs.bar2_xlat	 = SOC_SBAR2XLAT_OFFSET;
	ntb->reg_ofs.bar4_xlat	 = SOC_SBAR4XLAT_OFFSET;
	ntb->reg_ofs.lnk_cntl	 = SOC_NTBCNTL_OFFSET;
	ntb->reg_ofs.lnk_stat	 = SOC_LINK_STATUS_OFFSET;
	ntb->reg_ofs.spad_local	 = SOC_SPAD_OFFSET;
	ntb->reg_ofs.spad_remote = SOC_B2B_SPAD_OFFSET;
	ntb->reg_ofs.spci_cmd	 = SOC_PCICMD_OFFSET;

	ntb->limits.max_spads	 = SOC_MAX_SPADS;
	ntb->limits.max_db_bits	 = SOC_MAX_DB_BITS;
	ntb->limits.msix_cnt	 = SOC_MSIX_CNT;
	ntb->bits_per_vector	 = SOC_DB_BITS_PER_VEC;

	/*
	 * FIXME - MSI-X bug on early SOC HW, remove once internal issue is
	 * resolved.  Mask transaction layer internal parity errors.
	 */
	pci_write_config(ntb->device, 0xFC, 0x4, 4);

	configure_soc_secondary_side_bars(ntb);

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

	callout_reset(&ntb->heartbeat_timer, 0, ntb_handle_heartbeat, ntb);

	return (0);
}
Esempio n. 9
0
static void
handle_xeon_irq(void *arg)
{
	struct ntb_db_cb *db_cb = arg;
	struct ntb_softc *ntb = db_cb->ntb;

	/*
	 * On Xeon, there are 16 bits in the interrupt register
	 * but only 4 vectors.  So, 5 bits are assigned to the first 3
	 * vectors, with the 4th having a single bit for link
	 * interrupts.
	 */
	ntb_reg_write(2, ntb->reg_ofs.pdb,
	    ((1 << ntb->bits_per_vector) - 1) <<
	    (db_cb->db_num * ntb->bits_per_vector));

	if (db_cb->callback != NULL)
		db_cb->callback(db_cb->data, db_cb->db_num);
}
Esempio n. 10
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);
}
Esempio n. 11
0
static void
configure_xeon_secondary_side_bars(struct ntb_softc *ntb)
{

	if (ntb->dev_type == NTB_DEV_USD) {
		ntb_reg_write(8, XEON_PBAR2XLAT_OFFSET, PBAR2XLAT_USD_ADDR);
		if (HAS_FEATURE(NTB_REGS_THRU_MW))
			ntb_reg_write(8, XEON_PBAR4XLAT_OFFSET,
			    MBAR01_DSD_ADDR);
		else
			ntb_reg_write(8, XEON_PBAR4XLAT_OFFSET,
			    PBAR4XLAT_USD_ADDR);
		ntb_reg_write(8, XEON_SBAR0BASE_OFFSET, MBAR01_USD_ADDR);
		ntb_reg_write(8, XEON_SBAR2BASE_OFFSET, MBAR23_USD_ADDR);
		ntb_reg_write(8, XEON_SBAR4BASE_OFFSET, MBAR45_USD_ADDR);
	} else {
		ntb_reg_write(8, XEON_PBAR2XLAT_OFFSET, PBAR2XLAT_DSD_ADDR);
		if (HAS_FEATURE(NTB_REGS_THRU_MW))
			ntb_reg_write(8, XEON_PBAR4XLAT_OFFSET,
			    MBAR01_USD_ADDR);
		else
			ntb_reg_write(8, XEON_PBAR4XLAT_OFFSET,
			    PBAR4XLAT_DSD_ADDR);
		ntb_reg_write(8, XEON_SBAR0BASE_OFFSET, MBAR01_DSD_ADDR);
		ntb_reg_write(8, XEON_SBAR2BASE_OFFSET, MBAR23_DSD_ADDR);
		ntb_reg_write(8, XEON_SBAR4BASE_OFFSET, MBAR45_DSD_ADDR);
	}
}
Esempio n. 12
0
static int
ntb_setup_soc(struct ntb_softc *ntb)
{
	uint32_t val, connection_type;

	val = pci_read_config(ntb->device, NTB_PPD_OFFSET, 4);

	connection_type = (val & SOC_PPD_CONN_TYPE) >> 8;
	switch (connection_type) {
	case NTB_CONN_B2B:
		ntb->conn_type = NTB_CONN_B2B;
		break;
	case NTB_CONN_RP:
	default:
		device_printf(ntb->device, "Connection type %d not supported\n",
		    connection_type);
		return (ENXIO);
	}

	if ((val & SOC_PPD_DEV_TYPE) != 0)
		ntb->dev_type = NTB_DEV_DSD;
	else
		ntb->dev_type = NTB_DEV_USD;

	/* Initiate PCI-E link training */
	pci_write_config(ntb->device, NTB_PPD_OFFSET, val | SOC_PPD_INIT_LINK,
	    4);

	ntb->reg_ofs.pdb	 = SOC_PDOORBELL_OFFSET;
	ntb->reg_ofs.pdb_mask	 = SOC_PDBMSK_OFFSET;
	ntb->reg_ofs.sbar2_xlat  = SOC_SBAR2XLAT_OFFSET;
	ntb->reg_ofs.sbar4_xlat  = SOC_SBAR4XLAT_OFFSET;
	ntb->reg_ofs.lnk_cntl	 = SOC_NTBCNTL_OFFSET;
	ntb->reg_ofs.lnk_stat	 = SOC_LINK_STATUS_OFFSET;
	ntb->reg_ofs.spad_local	 = SOC_SPAD_OFFSET;
	ntb->reg_ofs.spci_cmd	 = SOC_PCICMD_OFFSET;

	if (ntb->conn_type == NTB_CONN_B2B) {
		ntb->reg_ofs.sdb	 = SOC_B2B_DOORBELL_OFFSET;
		ntb->reg_ofs.spad_remote = SOC_B2B_SPAD_OFFSET;
		ntb->limits.max_spads	 = SOC_MAX_SPADS;
	} else {
		ntb->reg_ofs.sdb	 = SOC_PDOORBELL_OFFSET;
		ntb->reg_ofs.spad_remote = SOC_SPAD_OFFSET;
		ntb->limits.max_spads	 = SOC_MAX_COMPAT_SPADS;
	}

	ntb->limits.max_db_bits  = SOC_MAX_DB_BITS;
	ntb->limits.msix_cnt	 = SOC_MSIX_CNT;
	ntb->bits_per_vector	 = SOC_DB_BITS_PER_VEC;

	/*
	 * FIXME - MSI-X bug on early SOC HW, remove once internal issue is
	 * resolved.  Mask transaction layer internal parity errors.
	 */
	pci_write_config(ntb->device, 0xFC, 0x4, 4);

	configure_soc_secondary_side_bars(ntb);

	/* Enable Bus Master and Memory Space on the secondary side */
	ntb_reg_write(2, ntb->reg_ofs.spci_cmd,
	    PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN);
	callout_reset(&ntb->heartbeat_timer, 0, ntb_handle_heartbeat, ntb);

	return (0);
}
Esempio n. 13
0
static int
ntb_setup_interrupts(struct ntb_softc *ntb)
{
	void (*interrupt_handler)(void *);
	void *int_arg;
	bool use_msix = 0;
	uint32_t num_vectors;
	int i;

	ntb->allocated_interrupts = 0;
	/*
	 * On SOC, disable all interrupts.  On XEON, disable all but Link
	 * Interrupt.  The rest will be unmasked as callbacks are registered.
	 */
	if (ntb->type == NTB_SOC)
		ntb_reg_write(8, ntb->reg_ofs.pdb_mask, ~0);
	else
		ntb_reg_write(2, ntb->reg_ofs.pdb_mask,
		    ~(1 << ntb->limits.max_db_bits));

	num_vectors = MIN(pci_msix_count(ntb->device),
	    ntb->limits.max_db_bits);
	if (num_vectors >= 1) {
		pci_alloc_msix(ntb->device, &num_vectors);
		if (num_vectors >= 4)
			use_msix = TRUE;
	}

	ntb_create_callbacks(ntb, num_vectors);
	if (use_msix == TRUE) {
		for (i = 0; i < num_vectors; i++) {
			ntb->int_info[i].rid = i + 1;
			ntb->int_info[i].res = bus_alloc_resource_any(
			    ntb->device, SYS_RES_IRQ, &ntb->int_info[i].rid,
			    RF_ACTIVE);
			if (ntb->int_info[i].res == NULL) {
				device_printf(ntb->device,
				    "bus_alloc_resource failed\n");
				return (-1);
			}
			ntb->int_info[i].tag = NULL;
			ntb->allocated_interrupts++;
			if (ntb->type == NTB_SOC) {
				interrupt_handler = handle_soc_irq;
				int_arg = &ntb->db_cb[i];
			} else {
				if (i == num_vectors - 1) {
					interrupt_handler =
					    handle_xeon_event_irq;
					int_arg = ntb;
				} else {
					interrupt_handler =
					    handle_xeon_irq;
					int_arg = &ntb->db_cb[i];
				}
			}
			if (bus_setup_intr(ntb->device, ntb->int_info[i].res,
			    INTR_MPSAFE | INTR_TYPE_MISC, NULL,
			    interrupt_handler, int_arg,
			    &ntb->int_info[i].tag) != 0) {
				device_printf(ntb->device,
				    "bus_setup_intr failed\n");
				return (ENXIO);
			}
		}
	}
	else {
		ntb->int_info[0].rid = 0;
		ntb->int_info[0].res = bus_alloc_resource_any(ntb->device,
		    SYS_RES_IRQ, &ntb->int_info[0].rid, RF_SHAREABLE|RF_ACTIVE);
		interrupt_handler = ntb_handle_legacy_interrupt;
		if (ntb->int_info[0].res == NULL) {
			device_printf(ntb->device,
			    "bus_alloc_resource failed\n");
			return (-1);
		}
		ntb->int_info[0].tag = NULL;
		ntb->allocated_interrupts = 1;

		if (bus_setup_intr(ntb->device, ntb->int_info[0].res,
			INTR_MPSAFE | INTR_TYPE_MISC, NULL,
			interrupt_handler, ntb, &ntb->int_info[0].tag) != 0) {

			device_printf(ntb->device, "bus_setup_intr failed\n");
			return (ENXIO);
		}
	}

	return (0);
}