コード例 #1
0
static int
vtpci_alloc_msix(struct vtpci_softc *sc, int nvectors)
{
	device_t dev;
	int nmsix, cnt, required;

	dev = sc->vtpci_dev;

	nmsix = pci_msix_count(dev);
	if (nmsix < 1)
		return (1);

	/* An additional vector is needed for the config changes. */
	required = nvectors + 1;
	if (nmsix >= required) {
		cnt = required;
		if (pci_alloc_msix(dev, &cnt) == 0 && cnt >= required)
			goto out;

		pci_release_msi(dev);
	}

	/* Attempt shared MSIX configuration. */
	required = 2;
	if (nmsix >= required) {
		cnt = required;
		if (pci_alloc_msix(dev, &cnt) == 0 && cnt >= required) {
			sc->vtpci_flags |= VIRTIO_PCI_FLAG_SHARED_MSIX;
			goto out;
		}

		pci_release_msi(dev);
	}

	return (1);

out:
	sc->vtpci_nintr_res = required;
	sc->vtpci_flags |= VIRTIO_PCI_FLAG_MSIX;

	if (bootverbose) {
		if (sc->vtpci_flags & VIRTIO_PCI_FLAG_SHARED_MSIX)
			device_printf(dev, "using shared virtqueue MSIX\n");
		else
			device_printf(dev, "using per virtqueue MSIX\n");
	}

	return (0);
}
コード例 #2
0
ファイル: isci_interrupt.c プロジェクト: coyizumi/cs111
void
isci_interrupt_setup(struct isci_softc *isci)
{
	uint8_t max_msix_messages = SCI_MAX_MSIX_MESSAGES_PER_CONTROLLER *
	    isci->controller_count;
	BOOL use_msix = FALSE;
	uint32_t force_legacy_interrupts = 0;

	TUNABLE_INT_FETCH("hw.isci.force_legacy_interrupts",
	    &force_legacy_interrupts);

	if (!force_legacy_interrupts &&
	    pci_msix_count(isci->device) >= max_msix_messages) {

		isci->num_interrupts = max_msix_messages;
		pci_alloc_msix(isci->device, &isci->num_interrupts);
		if (isci->num_interrupts == max_msix_messages)
			use_msix = TRUE;
	}

	if (use_msix == TRUE)
		isci_interrupt_setup_msix(isci);
	else
		isci_interrupt_setup_legacy(isci);
}
コード例 #3
0
ファイル: virtio_pci.c プロジェクト: 2asoft/freebsd
static int
vtpci_alloc_msix(struct vtpci_softc *sc, int nvectors)
{
	device_t dev;
	int nmsix, cnt, required;

	dev = sc->vtpci_dev;

	/* Allocate an additional vector for the config changes. */
	required = nvectors + 1;

	nmsix = pci_msix_count(dev);
	if (nmsix < required)
		return (1);

	cnt = required;
	if (pci_alloc_msix(dev, &cnt) == 0 && cnt >= required) {
		sc->vtpci_nmsix_resources = required;
		return (0);
	}

	pci_release_msi(dev);

	return (1);
}
コード例 #4
0
static int
ciss_setup_msix(struct ciss_softc *sc)
{
	int i, count, error;

	i = ciss_lookup(sc->ciss_dev);
	if (ciss_vendor_data[i].flags & CISS_BOARD_NOMSI)
		return (EINVAL);

	count = pci_msix_count(sc->ciss_dev);
	if (count < CISS_MSI_COUNT) {
		count = pci_msi_count(sc->ciss_dev);
		if (count < CISS_MSI_COUNT)
			return (EINVAL);
	}

	count = MIN(count, CISS_MSI_COUNT);
	error = pci_alloc_msix(sc->ciss_dev, &count);
	if (error) {
		error = pci_alloc_msi(sc->ciss_dev, &count);
		if (error)
			return (EINVAL);
	}

	sc->ciss_msi = count;
	for (i = 0; i < count; i++)
		sc->ciss_irq_rid[i] = i + 1;

	return (0);
}
コード例 #5
0
	/* Allocate the parent DMA tag */
	if (bus_dma_tag_create(NULL,			/* parent */
				1, 0,			/* algnmnt, boundary */
				BUS_SPACE_MAXADDR,	/* lowaddr */
				BUS_SPACE_MAXADDR,	/* highaddr */
				NULL, NULL,		/* filter, filterarg */
				BUS_SPACE_MAXSIZE_32BIT,/* maxsize */
				BUS_SPACE_UNRESTRICTED,	/* nsegments */
				BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
				0,			/* flags */
				&sc->mps_parent_dmat)) {
		device_printf(dev, "Cannot allocate parent DMA tag\n");
		mps_pci_free(sc);
		return (ENOMEM);
	}

	if ((error = mps_attach(sc)) != 0)
		mps_pci_free(sc);

	return (error);
}

int
mps_pci_setup_interrupts(struct mps_softc *sc)
{
	device_t dev;
	int error;
	u_int irq_flags;

	dev = sc->mps_dev;
#if 0 /* XXX swildner */
	if ((sc->disable_msix == 0) &&
	    ((msgs = pci_msix_count(dev)) >= MPS_MSI_COUNT))
		error = mps_alloc_msix(sc, MPS_MSI_COUNT);
#endif

	sc->mps_irq_rid[0] = 0;
	sc->mps_irq_type[0] = pci_alloc_1intr(dev, sc->enable_msi,
	    &sc->mps_irq_rid[0], &irq_flags);
	sc->mps_irq[0] = bus_alloc_resource_any(dev, SYS_RES_IRQ,
	    &sc->mps_irq_rid[0],  irq_flags);
	if (sc->mps_irq[0] == NULL) {
		device_printf(dev, "Cannot allocate interrupt\n");
		return (ENXIO);
	}
	error = bus_setup_intr(dev, sc->mps_irq[0], INTR_MPSAFE, mps_intr, sc,
	    &sc->mps_intrhand[0], NULL);
	if (error)
		device_printf(dev, "Cannot setup interrupt\n");

	return (error);
}

static int
mps_pci_detach(device_t dev)
{
	struct mps_softc *sc;
	int error;

	sc = device_get_softc(dev);

	if ((error = mps_free(sc)) != 0)
		return (error);

	mps_pci_free(sc);
	return (0);
}

static void
mps_pci_free(struct mps_softc *sc)
{
	if (sc->mps_parent_dmat != NULL) {
		bus_dma_tag_destroy(sc->mps_parent_dmat);
	}

	bus_teardown_intr(sc->mps_dev, sc->mps_irq[0], sc->mps_intrhand[0]);
	bus_release_resource(sc->mps_dev, SYS_RES_IRQ, sc->mps_irq_rid[0],
	    sc->mps_irq[0]);
	if (sc->mps_irq_type[0] == PCI_INTR_TYPE_MSI)
		pci_release_msi(sc->mps_dev);

	if (sc->mps_regs_resource != NULL) {
		bus_release_resource(sc->mps_dev, SYS_RES_MEMORY,
		    sc->mps_regs_rid, sc->mps_regs_resource);
	}

	return;
}

static int
mps_pci_suspend(device_t dev)
{
	return (EINVAL);
}

static int
mps_pci_resume(device_t dev)
{
	return (EINVAL);
}

#if 0 /* XXX swildner */
static int
mps_alloc_msix(struct mps_softc *sc, int msgs)
{
	int error;

	error = pci_alloc_msix(sc->mps_dev, &msgs);
	return (error);
}
コード例 #6
0
ファイル: ntb_hw.c プロジェクト: coderandy/freebsd
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);
}
コード例 #7
0
ファイル: vga_pci.c プロジェクト: rchander/freebsd
static int
vga_pci_alloc_msix(device_t dev, device_t child, int *count)
{
	struct vga_pci_softc *sc;
	int error;

	sc = device_get_softc(dev);
	if (sc->vga_msi_child != NULL)
		return (EBUSY);
	error = pci_alloc_msix(dev, count);
	if (error == 0)
		sc->vga_msi_child = child;
	return (error);
}
コード例 #8
0
ファイル: sfxge_intr.c プロジェクト: ele7enxxh/dtrace-pf
static int
sfxge_intr_setup_msix(struct sfxge_softc *sc)
{
	struct sfxge_intr *intr;
	struct resource *resp;
	device_t dev;
	int count;
	int rid;

	dev = sc->dev;
	intr = &sc->intr;

	/* Check if MSI-X is available. */
	count = pci_msix_count(dev);
	if (count == 0)
		return (EINVAL);

	/* Limit the number of interrupts to the number of CPUs. */
	if (count > mp_ncpus)
		count = mp_ncpus;

	/* Not very likely these days... */
	if (count > EFX_MAXRSS)
		count = EFX_MAXRSS;

	rid = PCIR_BAR(4);
	resp = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
	if (resp == NULL)
		return (ENOMEM);

	if (pci_alloc_msix(dev, &count) != 0) {
		bus_release_resource(dev, SYS_RES_MEMORY, rid, resp);
		return (ENOMEM);
	}

	/* Allocate interrupt handlers. */
	if (sfxge_intr_alloc(sc, count) != 0) {
		bus_release_resource(dev, SYS_RES_MEMORY, rid, resp);
		pci_release_msi(dev);
		return (ENOMEM);
	}

	intr->type = EFX_INTR_MESSAGE;
	intr->n_alloc = count;
	intr->msix_res = resp;

	return (0);
}
コード例 #9
0
ファイル: sfxge_intr.c プロジェクト: Digital-Chaos/freebsd
static int
sfxge_intr_setup_msix(struct sfxge_softc *sc)
{
	struct sfxge_intr *intr;
	struct resource *resp;
	device_t dev;
	int count;
	int rid;

	dev = sc->dev;
	intr = &sc->intr;

	/* Check if MSI-X is available. */
	count = pci_msix_count(dev);
	if (count == 0)
		return (EINVAL);

	/* Do not try to allocate more than already estimated EVQ maximum */
	KASSERT(sc->evq_max > 0, ("evq_max is zero"));
	count = MIN(count, sc->evq_max);

	rid = PCIR_BAR(4);
	resp = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
	if (resp == NULL)
		return (ENOMEM);

	if (pci_alloc_msix(dev, &count) != 0) {
		bus_release_resource(dev, SYS_RES_MEMORY, rid, resp);
		return (ENOMEM);
	}

	/* Allocate interrupt handlers. */
	if (sfxge_intr_alloc(sc, count) != 0) {
		bus_release_resource(dev, SYS_RES_MEMORY, rid, resp);
		pci_release_msi(dev);
		return (ENOMEM);
	}

	intr->type = EFX_INTR_MESSAGE;
	intr->n_alloc = count;
	intr->msix_res = resp;

	return (0);
}
コード例 #10
0
ファイル: ioat.c プロジェクト: cyrilmagsuci/freebsd
/*
 * Interrupt setup and handlers
 */
static int
ioat_setup_intr(struct ioat_softc *ioat)
{
	uint32_t num_vectors;
	int error;
	boolean_t use_msix;
	boolean_t force_legacy_interrupts;

	use_msix = FALSE;
	force_legacy_interrupts = FALSE;

	if (!g_force_legacy_interrupts && pci_msix_count(ioat->device) >= 1) {
		num_vectors = 1;
		pci_alloc_msix(ioat->device, &num_vectors);
		if (num_vectors == 1)
			use_msix = TRUE;
	}

	if (use_msix) {
		ioat->rid = 1;
		ioat->res = bus_alloc_resource_any(ioat->device, SYS_RES_IRQ,
		    &ioat->rid, RF_ACTIVE);
	} else {
		ioat->rid = 0;
		ioat->res = bus_alloc_resource_any(ioat->device, SYS_RES_IRQ,
		    &ioat->rid, RF_SHAREABLE | RF_ACTIVE);
	}
	if (ioat->res == NULL) {
		ioat_log_message(0, "bus_alloc_resource failed\n");
		return (ENOMEM);
	}

	ioat->tag = NULL;
	error = bus_setup_intr(ioat->device, ioat->res, INTR_MPSAFE |
	    INTR_TYPE_MISC, NULL, ioat_interrupt_handler, ioat, &ioat->tag);
	if (error != 0) {
		ioat_log_message(0, "bus_setup_intr failed\n");
		return (error);
	}

	ioat_write_intrctrl(ioat, IOAT_INTRCTRL_MASTER_INT_EN);
	return (0);
}
コード例 #11
0
ファイル: mpt_pci.c プロジェクト: AhmadTux/freebsd
static int
mpt_pci_attach(device_t dev)
{
	struct mpt_softc *mpt;
	int		  iqd;
	uint32_t	  data, cmd;
	int		  mpt_io_bar, mpt_mem_bar;

	mpt  = (struct mpt_softc*)device_get_softc(dev);

	switch (pci_get_device(dev)) {
	case MPI_MANUFACTPAGE_DEVICEID_FC909_FB:
	case MPI_MANUFACTPAGE_DEVICEID_FC909:
	case MPI_MANUFACTPAGE_DEVICEID_FC919:
	case MPI_MANUFACTPAGE_DEVICEID_FC919_LAN_FB:
	case MPI_MANUFACTPAGE_DEVICEID_FC929:
	case MPI_MANUFACTPAGE_DEVICEID_FC929_LAN_FB:
	case MPI_MANUFACTPAGE_DEVICEID_FC929X:
	case MPI_MANUFACTPAGE_DEVICEID_FC929X_LAN_FB:
	case MPI_MANUFACTPAGE_DEVICEID_FC919X:
	case MPI_MANUFACTPAGE_DEVICEID_FC919X_LAN_FB:
	case MPI_MANUFACTPAGE_DEVICEID_FC949E:
	case MPI_MANUFACTPAGE_DEVICEID_FC949X:
		mpt->is_fc = 1;
		break;
	case MPI_MANUFACTPAGE_DEVID_SAS1078:
	case MPI_MANUFACTPAGE_DEVID_SAS1078DE_FB:
		mpt->is_1078 = 1;
		/* FALLTHROUGH */
	case MPI_MANUFACTPAGE_DEVID_SAS1064:
	case MPI_MANUFACTPAGE_DEVID_SAS1064A:
	case MPI_MANUFACTPAGE_DEVID_SAS1064E:
	case MPI_MANUFACTPAGE_DEVID_SAS1066:
	case MPI_MANUFACTPAGE_DEVID_SAS1066E:
	case MPI_MANUFACTPAGE_DEVID_SAS1068:
	case MPI_MANUFACTPAGE_DEVID_SAS1068A_FB:
	case MPI_MANUFACTPAGE_DEVID_SAS1068E:
	case MPI_MANUFACTPAGE_DEVID_SAS1068E_FB:
		mpt->is_sas = 1;
		break;
	default:
		mpt->is_spi = 1;
		break;
	}
	mpt->dev = dev;
	mpt->unit = device_get_unit(dev);
	mpt->raid_resync_rate = MPT_RAID_RESYNC_RATE_DEFAULT;
	mpt->raid_mwce_setting = MPT_RAID_MWCE_DEFAULT;
	mpt->raid_queue_depth = MPT_RAID_QUEUE_DEPTH_DEFAULT;
	mpt->verbose = MPT_PRT_NONE;
	mpt->role = MPT_ROLE_NONE;
	mpt->mpt_ini_id = MPT_INI_ID_NONE;
#ifdef __sparc64__
	if (mpt->is_spi)
		mpt->mpt_ini_id = OF_getscsinitid(dev);
#endif
	mpt_set_options(mpt);
	if (mpt->verbose == MPT_PRT_NONE) {
		mpt->verbose = MPT_PRT_WARN;
		/* Print INFO level (if any) if bootverbose is set */
		mpt->verbose += (bootverbose != 0)? 1 : 0;
	}
	/* Make sure memory access decoders are enabled */
	cmd = pci_read_config(dev, PCIR_COMMAND, 2);
	if ((cmd & PCIM_CMD_MEMEN) == 0) {
		device_printf(dev, "Memory accesses disabled");
		return (ENXIO);
	}

	/*
	 * Make sure that SERR, PERR, WRITE INVALIDATE and BUSMASTER are set.
	 */
	cmd |=
	    PCIM_CMD_SERRESPEN | PCIM_CMD_PERRESPEN |
	    PCIM_CMD_BUSMASTEREN | PCIM_CMD_MWRICEN;
	pci_write_config(dev, PCIR_COMMAND, cmd, 2);

	/*
	 * Make sure we've disabled the ROM.
	 */
	data = pci_read_config(dev, PCIR_BIOS, 4);
	data &= ~PCIM_BIOS_ENABLE;
	pci_write_config(dev, PCIR_BIOS, data, 4);

	/*
	 * Is this part a dual?
	 * If so, link with our partner (around yet)
	 */
	switch (pci_get_device(dev)) {
	case MPI_MANUFACTPAGE_DEVICEID_FC929:
	case MPI_MANUFACTPAGE_DEVICEID_FC929_LAN_FB:
	case MPI_MANUFACTPAGE_DEVICEID_FC949E:
	case MPI_MANUFACTPAGE_DEVICEID_FC949X:
	case MPI_MANUFACTPAGE_DEVID_53C1030:
	case MPI_MANUFACTPAGE_DEVID_53C1030ZC:
		mpt_link_peer(mpt);
		break;
	default:
		break;
	}

	/*
	 * Figure out which are the I/O and MEM Bars
	 */
	data = pci_read_config(dev, PCIR_BAR(0), 4);
	if (PCI_BAR_IO(data)) {
		/* BAR0 is IO, BAR1 is memory */
		mpt_io_bar = 0;
		mpt_mem_bar = 1;
	} else {
		/* BAR0 is memory, BAR1 is IO */
		mpt_mem_bar = 0;
		mpt_io_bar = 1;
	}

	/*
	 * Set up register access.  PIO mode is required for
	 * certain reset operations (but must be disabled for
	 * some cards otherwise).
	 */
	mpt_io_bar = PCIR_BAR(mpt_io_bar);
	mpt->pci_pio_reg = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
	    &mpt_io_bar, RF_ACTIVE);
	if (mpt->pci_pio_reg == NULL) {
		if (bootverbose) {
			device_printf(dev,
			    "unable to map registers in PIO mode\n");
		}
	} else {
		mpt->pci_pio_st = rman_get_bustag(mpt->pci_pio_reg);
		mpt->pci_pio_sh = rman_get_bushandle(mpt->pci_pio_reg);
	}

	mpt_mem_bar = PCIR_BAR(mpt_mem_bar);
	mpt->pci_reg = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
	    &mpt_mem_bar, RF_ACTIVE);
	if (mpt->pci_reg == NULL) {
		if (bootverbose || mpt->is_sas || mpt->pci_pio_reg == NULL) {
			device_printf(dev,
			    "Unable to memory map registers.\n");
		}
		if (mpt->is_sas || mpt->pci_pio_reg == NULL) {
			device_printf(dev, "Giving Up.\n");
			goto bad;
		}
		if (bootverbose) {
			device_printf(dev, "Falling back to PIO mode.\n");
		}
		mpt->pci_st = mpt->pci_pio_st;
		mpt->pci_sh = mpt->pci_pio_sh;
	} else {
		mpt->pci_st = rman_get_bustag(mpt->pci_reg);
		mpt->pci_sh = rman_get_bushandle(mpt->pci_reg);
	}

	/* Get a handle to the interrupt */
	iqd = 0;
	if (mpt->msi_enable) {
		/*
		 * First try to alloc an MSI-X message.  If that
		 * fails, then try to alloc an MSI message instead.
		 */
		if (pci_msix_count(dev) == 1) {
			mpt->pci_msi_count = 1;
			if (pci_alloc_msix(dev, &mpt->pci_msi_count) == 0) {
				iqd = 1;
			} else {
				mpt->pci_msi_count = 0;
			}
		}
		if (iqd == 0 && pci_msi_count(dev) == 1) {
			mpt->pci_msi_count = 1;
			if (pci_alloc_msi(dev, &mpt->pci_msi_count) == 0) {
				iqd = 1;
			} else {
				mpt->pci_msi_count = 0;
			}
		}
	}
	mpt->pci_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &iqd,
	    RF_ACTIVE | (mpt->pci_msi_count ? 0 : RF_SHAREABLE));
	if (mpt->pci_irq == NULL) {
		device_printf(dev, "could not allocate interrupt\n");
		goto bad;
	}

	MPT_LOCK_SETUP(mpt);

	/* Disable interrupts at the part */
	mpt_disable_ints(mpt);

	/* Register the interrupt handler */
	if (mpt_setup_intr(dev, mpt->pci_irq, MPT_IFLAGS, NULL, mpt_pci_intr,
	    mpt, &mpt->ih)) {
		device_printf(dev, "could not setup interrupt\n");
		goto bad;
	}

	/* Allocate dma memory */
	if (mpt_dma_mem_alloc(mpt)) {
		mpt_prt(mpt, "Could not allocate DMA memory\n");
		goto bad;
	}

#if 0
	/*
	 * Save the PCI config register values
 	 *
	 * Hard resets are known to screw up the BAR for diagnostic
	 * memory accesses (Mem1).
	 *
	 * Using Mem1 is known to make the chip stop responding to 
	 * configuration space transfers, so we need to save it now
	 */

	mpt_read_config_regs(mpt);
#endif

	/*
	 * Disable PIO until we need it
	 */
	if (mpt->is_sas) {
		pci_disable_io(dev, SYS_RES_IOPORT);
	}

	/* Initialize the hardware */
	if (mpt->disabled == 0) {
		if (mpt_attach(mpt) != 0) {
			goto bad;
		}
	} else {
		mpt_prt(mpt, "device disabled at user request\n");
		goto bad;
	}

	mpt->eh = EVENTHANDLER_REGISTER(shutdown_post_sync, mpt_pci_shutdown,
	    dev, SHUTDOWN_PRI_DEFAULT);

	if (mpt->eh == NULL) {
		mpt_prt(mpt, "shutdown event registration failed\n");
		(void) mpt_detach(mpt);
		goto bad;
	}
	return (0);

bad:
	mpt_dma_mem_free(mpt);
	mpt_free_bus_resources(mpt);
	mpt_unlink_peer(mpt);

	MPT_LOCK_DESTROY(mpt);

	/*
	 * but return zero to preserve unit numbering
	 */
	return (0);
}
コード例 #12
0
ファイル: ppt.c プロジェクト: ele7enxxh/dtrace-pf
int
ppt_setup_msix(struct vm *vm, int vcpu, int bus, int slot, int func,
	       int idx, uint64_t addr, uint64_t msg, uint32_t vector_control)
{
	struct pptdev *ppt;
	struct pci_devinfo *dinfo;
	int numvec, alloced, rid, error;
	size_t res_size, cookie_size, arg_size;

	ppt = ppt_find(bus, slot, func);
	if (ppt == NULL)
		return (ENOENT);
	if (ppt->vm != vm)		/* Make sure we own this device */
		return (EBUSY);

	dinfo = device_get_ivars(ppt->dev);
	if (!dinfo) 
		return (ENXIO);

	/* 
	 * First-time configuration:
	 * 	Allocate the MSI-X table
	 *	Allocate the IRQ resources
	 *	Set up some variables in ppt->msix
	 */
	if (ppt->msix.num_msgs == 0) {
		numvec = pci_msix_count(ppt->dev);
		if (numvec <= 0)
			return (EINVAL);

		ppt->msix.startrid = 1;
		ppt->msix.num_msgs = numvec;

		res_size = numvec * sizeof(ppt->msix.res[0]);
		cookie_size = numvec * sizeof(ppt->msix.cookie[0]);
		arg_size = numvec * sizeof(ppt->msix.arg[0]);

		ppt->msix.res = malloc(res_size, M_PPTMSIX, M_WAITOK | M_ZERO);
		ppt->msix.cookie = malloc(cookie_size, M_PPTMSIX,
					  M_WAITOK | M_ZERO);
		ppt->msix.arg = malloc(arg_size, M_PPTMSIX, M_WAITOK | M_ZERO);

		rid = dinfo->cfg.msix.msix_table_bar;
		ppt->msix.msix_table_res = bus_alloc_resource_any(ppt->dev,
					       SYS_RES_MEMORY, &rid, RF_ACTIVE);

		if (ppt->msix.msix_table_res == NULL) {
			ppt_teardown_msix(ppt);
			return (ENOSPC);
		}
		ppt->msix.msix_table_rid = rid;

		alloced = numvec;
		error = pci_alloc_msix(ppt->dev, &alloced);
		if (error || alloced != numvec) {
			ppt_teardown_msix(ppt);
			return (error == 0 ? ENOSPC: error);
		}
	}

	if ((vector_control & PCIM_MSIX_VCTRL_MASK) == 0) {
		/* Tear down the IRQ if it's already set up */
		ppt_teardown_msix_intr(ppt, idx);

		/* Allocate the IRQ resource */
		ppt->msix.cookie[idx] = NULL;
		rid = ppt->msix.startrid + idx;
		ppt->msix.res[idx] = bus_alloc_resource_any(ppt->dev, SYS_RES_IRQ,
							    &rid, RF_ACTIVE);
		if (ppt->msix.res[idx] == NULL)
			return (ENXIO);
	
		ppt->msix.arg[idx].pptdev = ppt;
		ppt->msix.arg[idx].addr = addr;
		ppt->msix.arg[idx].msg_data = msg;
	
		/* Setup the MSI-X interrupt */
		error = bus_setup_intr(ppt->dev, ppt->msix.res[idx],
				       INTR_TYPE_NET | INTR_MPSAFE,
				       pptintr, NULL, &ppt->msix.arg[idx],
				       &ppt->msix.cookie[idx]);
	
		if (error != 0) {
			bus_teardown_intr(ppt->dev, ppt->msix.res[idx], ppt->msix.cookie[idx]);
			bus_release_resource(ppt->dev, SYS_RES_IRQ, rid, ppt->msix.res[idx]);
			ppt->msix.cookie[idx] = NULL;
			ppt->msix.res[idx] = NULL;
			return (ENXIO);
		}
	} else {
		/* Masked, tear it down if it's already been set up */
		ppt_teardown_msix_intr(ppt, idx);
	}

	return (0);
}
コード例 #13
0
ファイル: ntb_hw.c プロジェクト: Ricky54326/freebsd
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);
}
コード例 #14
0
ファイル: ntb_hw.c プロジェクト: Alkzndr/freebsd
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);
}