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