Example #1
0
static void
unmask_ldb_interrupt(struct ntb_softc *ntb, unsigned int idx)
{
	uint64_t mask;

	mask = db_ioread(ntb, ntb->reg_ofs.ldb_mask);
	mask &= ~(1 << (idx * ntb->bits_per_vector));
	db_iowrite(ntb, ntb->reg_ofs.ldb_mask, mask);
}
Example #2
0
static int
ntb_setup_interrupts(struct ntb_softc *ntb)
{
	uint32_t desired_vectors, num_vectors;
	uint64_t mask;
	int rc;

	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.
	 */
	mask = 0;
	if (ntb->type == NTB_XEON)
		mask = (1 << XEON_LINK_DB);
	db_iowrite(ntb, ntb->reg_ofs.ldb_mask, ~mask);

	num_vectors = desired_vectors = MIN(pci_msix_count(ntb->device),
	    ntb->limits.max_db_bits);
	if (desired_vectors >= 1) {
		rc = pci_alloc_msix(ntb->device, &num_vectors);

		if (ntb_force_remap_mode != 0 && rc == 0 &&
		    num_vectors == desired_vectors)
			num_vectors--;

		if (rc == 0 && num_vectors < desired_vectors) {
			rc = ntb_remap_msix(ntb->device, desired_vectors,
			    num_vectors);
			if (rc == 0)
				num_vectors = desired_vectors;
			else
				pci_release_msi(ntb->device);
		}
		if (rc != 0)
			num_vectors = 1;
	} else
		num_vectors = 1;

	ntb_create_callbacks(ntb, num_vectors);

	if (ntb->type == NTB_XEON)
		rc = ntb_setup_xeon_msix(ntb, num_vectors);
	else
		rc = ntb_setup_soc_msix(ntb, num_vectors);
	if (rc != 0)
		device_printf(ntb->device,
		    "Error allocating MSI-X interrupts: %d\n", rc);

	if (ntb->type == NTB_XEON && rc == ENOSPC)
		rc = ntb_setup_legacy_interrupt(ntb);

	return (rc);
}
Example #3
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 */
	db_iowrite(ntb, ntb->reg_ofs.ldb, 1 << XEON_LINK_DB);
}
Example #4
0
static void
handle_soc_irq(void *arg)
{
	struct ntb_db_cb *db_cb = arg;
	struct ntb_softc *ntb = db_cb->ntb;

	db_iowrite(ntb, ntb->reg_ofs.ldb, (uint64_t) 1 << db_cb->db_num);

	if (db_cb->callback != NULL) {
		mask_ldb_interrupt(ntb, db_cb->db_num);
		callout_reset(&db_cb->irq_work, 0, ntb_irq_work, db_cb);
	}
}
Example #5
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.
	 */
	db_iowrite(ntb, ntb->reg_ofs.ldb,
	    ((1 << ntb->bits_per_vector) - 1) <<
	    (db_cb->db_num * ntb->bits_per_vector));

	if (db_cb->callback != NULL) {
		mask_ldb_interrupt(ntb, db_cb->db_num);
		callout_reset(&db_cb->irq_work, 0, ntb_irq_work, db_cb);
	}
}
Example #6
0
static int
ntb_setup_interrupts(struct ntb_softc *ntb)
{
	uint32_t desired_vectors, num_vectors;
	uint64_t mask;
	int rc;

	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.
	 */
	mask = 0;
	if (ntb->type == NTB_XEON)
		mask = (1 << XEON_LINK_DB);
	db_iowrite(ntb, ntb->reg_ofs.ldb_mask, ~mask);

	num_vectors = desired_vectors = MIN(pci_msix_count(ntb->device),
	    ntb->limits.max_db_bits);
	if (desired_vectors >= 1) {
		rc = pci_alloc_msix(ntb->device, &num_vectors);

		if (ntb_force_remap_mode != 0 && rc == 0 &&
		    num_vectors == desired_vectors)
			num_vectors--;

		if (rc == 0 && num_vectors < desired_vectors) {
			rc = ntb_remap_msix(ntb->device, desired_vectors,
			    num_vectors);
			if (rc == 0)
				num_vectors = desired_vectors;
			else
				pci_release_msi(ntb->device);
		}
		if (rc != 0)
			num_vectors = 1;
	} else
		num_vectors = 1;

	/*
	 * If allocating MSI-X interrupts succeeds, limit callbacks to the
	 * number of MSI-X slots available.
	 */
	ntb_create_callbacks(ntb, num_vectors);

	if (ntb->type == NTB_XEON)
		rc = ntb_setup_xeon_msix(ntb, num_vectors);
	else
		rc = ntb_setup_soc_msix(ntb, num_vectors);
	if (rc != 0) {
		device_printf(ntb->device,
		    "Error allocating MSI-X interrupts: %d\n", rc);

		/*
		 * If allocating MSI-X interrupts failed and we're forced to
		 * use legacy INTx anyway, the only limit on individual
		 * callbacks is the number of doorbell bits.
		 *
		 * CEM: This seems odd to me but matches the behavior of the
		 * Linux driver ca. September 2013
		 */
		ntb_free_callbacks(ntb);
		ntb_create_callbacks(ntb, ntb->limits.max_db_bits);
	}

	if (ntb->type == NTB_XEON && rc == ENOSPC)
		rc = ntb_setup_legacy_interrupt(ntb);

	return (rc);
}