igb_receive_internal(IGBCore *core, const struct iovec *iov, int iovcnt,
bool has_vnet, bool *external_tx);
-static inline void
-igb_set_interrupt_cause(IGBCore *core, uint32_t val);
-
-static void igb_update_interrupt_state(IGBCore *core);
+static void igb_raise_interrupts(IGBCore *core, size_t index, uint32_t causes);
static void igb_reset(IGBCore *core, bool sw);
static inline void
}
if (eic) {
- core->mac[EICR] |= eic;
- igb_set_interrupt_cause(core, E1000_ICR_TXDW);
+ igb_raise_interrupts(core, EICR, eic);
+ igb_raise_interrupts(core, ICR, E1000_ICR_TXDW);
}
net_tx_pkt_reset(txr->tx->tx_pkt, net_tx_pkt_unmap_frag_pci, d);
{
uint16_t queues = 0;
uint32_t causes = 0;
+ uint32_t ecauses = 0;
union {
L2Header l2_header;
uint8_t octets[ETH_ZLEN];
causes |= E1000_ICS_RXDMT0;
}
- core->mac[EICR] |= igb_rx_wb_eic(core, rxr.i->idx);
+ ecauses |= igb_rx_wb_eic(core, rxr.i->idx);
trace_e1000e_rx_written_to_guest(rxr.i->idx);
}
trace_e1000e_rx_interrupt_set(causes);
- igb_set_interrupt_cause(core, causes);
+ igb_raise_interrupts(core, EICR, ecauses);
+ igb_raise_interrupts(core, ICR, causes);
return orig_size;
}
}
if (core->mac[STATUS] != old_status) {
- igb_set_interrupt_cause(core, E1000_ICR_LSC);
+ igb_raise_interrupts(core, ICR, E1000_ICR_LSC);
}
}
}
}
-static inline void
-igb_clear_ims_bits(IGBCore *core, uint32_t bits)
-{
- trace_e1000e_irq_clear_ims(bits, core->mac[IMS], core->mac[IMS] & ~bits);
- core->mac[IMS] &= ~bits;
-}
-
static inline bool
igb_postpone_interrupt(IGBIntrDelayTimer *timer)
{
return igb_postpone_interrupt(&core->eitr[idx]);
}
-static void igb_send_msix(IGBCore *core)
+static void igb_send_msix(IGBCore *core, uint32_t causes)
{
- uint32_t causes = core->mac[EICR] & core->mac[EIMS];
int vector;
for (vector = 0; vector < IGB_INTR_NUM; ++vector) {
trace_e1000e_irq_fix_icr_asserted(core->mac[ICR]);
}
-static void
-igb_update_interrupt_state(IGBCore *core)
+static void igb_raise_interrupts(IGBCore *core, size_t index, uint32_t causes)
{
- uint32_t icr;
- uint32_t causes;
+ uint32_t old_causes = core->mac[ICR] & core->mac[IMS];
+ uint32_t old_ecauses = core->mac[EICR] & core->mac[EIMS];
+ uint32_t raised_causes;
+ uint32_t raised_ecauses;
uint32_t int_alloc;
- icr = core->mac[ICR] & core->mac[IMS];
+ trace_e1000e_irq_set(index << 2,
+ core->mac[index], core->mac[index] | causes);
+
+ core->mac[index] |= causes;
if (core->mac[GPIE] & E1000_GPIE_MSIX_MODE) {
- if (icr) {
- causes = 0;
- if (icr & E1000_ICR_DRSTA) {
- int_alloc = core->mac[IVAR_MISC] & 0xff;
- if (int_alloc & E1000_IVAR_VALID) {
- causes |= BIT(int_alloc & 0x1f);
- }
+ raised_causes = core->mac[ICR] & core->mac[IMS] & ~old_causes;
+
+ if (raised_causes & E1000_ICR_DRSTA) {
+ int_alloc = core->mac[IVAR_MISC] & 0xff;
+ if (int_alloc & E1000_IVAR_VALID) {
+ core->mac[EICR] |= BIT(int_alloc & 0x1f);
}
- /* Check if other bits (excluding the TCP Timer) are enabled. */
- if (icr & ~E1000_ICR_DRSTA) {
- int_alloc = (core->mac[IVAR_MISC] >> 8) & 0xff;
- if (int_alloc & E1000_IVAR_VALID) {
- causes |= BIT(int_alloc & 0x1f);
- }
- trace_e1000e_irq_add_msi_other(core->mac[EICR]);
+ }
+ /* Check if other bits (excluding the TCP Timer) are enabled. */
+ if (raised_causes & ~E1000_ICR_DRSTA) {
+ int_alloc = (core->mac[IVAR_MISC] >> 8) & 0xff;
+ if (int_alloc & E1000_IVAR_VALID) {
+ core->mac[EICR] |= BIT(int_alloc & 0x1f);
}
- core->mac[EICR] |= causes;
}
- if ((core->mac[EICR] & core->mac[EIMS])) {
- igb_send_msix(core);
+ raised_ecauses = core->mac[EICR] & core->mac[EIMS] & ~old_ecauses;
+ if (!raised_ecauses) {
+ return;
}
+
+ igb_send_msix(core, raised_ecauses);
} else {
igb_fix_icr_asserted(core);
- if (icr) {
- core->mac[EICR] |= (icr & E1000_ICR_DRSTA) | E1000_EICR_OTHER;
- } else {
- core->mac[EICR] &= ~E1000_EICR_OTHER;
+ raised_causes = core->mac[ICR] & core->mac[IMS] & ~old_causes;
+ if (!raised_causes) {
+ return;
}
- trace_e1000e_irq_pending_interrupts(core->mac[ICR] & core->mac[IMS],
- core->mac[ICR], core->mac[IMS]);
+ core->mac[EICR] |= (raised_causes & E1000_ICR_DRSTA) | E1000_EICR_OTHER;
if (msix_enabled(core->owner)) {
- if (icr) {
- trace_e1000e_irq_msix_notify_vec(0);
- msix_notify(core->owner, 0);
- }
+ trace_e1000e_irq_msix_notify_vec(0);
+ msix_notify(core->owner, 0);
} else if (msi_enabled(core->owner)) {
- if (icr) {
- msi_notify(core->owner, 0);
- }
+ trace_e1000e_irq_msi_notify(raised_causes);
+ msi_notify(core->owner, 0);
} else {
- if (icr) {
- igb_raise_legacy_irq(core);
- } else {
- igb_lower_legacy_irq(core);
- }
+ igb_raise_legacy_irq(core);
}
}
}
-static void
-igb_set_interrupt_cause(IGBCore *core, uint32_t val)
+static void igb_lower_interrupts(IGBCore *core, size_t index, uint32_t causes)
{
- trace_e1000e_irq_set_cause_entry(val, core->mac[ICR]);
+ trace_e1000e_irq_clear(index << 2,
+ core->mac[index], core->mac[index] & ~causes);
+
+ core->mac[index] &= ~causes;
- core->mac[ICR] |= val;
+ trace_e1000e_irq_pending_interrupts(core->mac[ICR] & core->mac[IMS],
+ core->mac[ICR], core->mac[IMS]);
- trace_e1000e_irq_set_cause_exit(val, core->mac[ICR]);
+ if (!(core->mac[ICR] & core->mac[IMS]) &&
+ !(core->mac[GPIE] & E1000_GPIE_MSIX_MODE)) {
+ core->mac[EICR] &= ~E1000_EICR_OTHER;
- igb_update_interrupt_state(core);
+ if (!msix_enabled(core->owner) && !msi_enabled(core->owner)) {
+ igb_lower_legacy_irq(core);
+ }
+ }
}
static void igb_set_eics(IGBCore *core, int index, uint32_t val)
{
bool msix = !!(core->mac[GPIE] & E1000_GPIE_MSIX_MODE);
+ uint32_t mask = msix ? E1000_EICR_MSIX_MASK : E1000_EICR_LEGACY_MASK;
trace_igb_irq_write_eics(val, msix);
-
- core->mac[EICS] |=
- val & (msix ? E1000_EICR_MSIX_MASK : E1000_EICR_LEGACY_MASK);
-
- /*
- * TODO: Move to igb_update_interrupt_state if EICS is modified in other
- * places.
- */
- core->mac[EICR] = core->mac[EICS];
-
- igb_update_interrupt_state(core);
+ igb_raise_interrupts(core, EICR, val & mask);
}
static void igb_set_eims(IGBCore *core, int index, uint32_t val)
{
bool msix = !!(core->mac[GPIE] & E1000_GPIE_MSIX_MODE);
+ uint32_t mask = msix ? E1000_EICR_MSIX_MASK : E1000_EICR_LEGACY_MASK;
trace_igb_irq_write_eims(val, msix);
-
- core->mac[EIMS] |=
- val & (msix ? E1000_EICR_MSIX_MASK : E1000_EICR_LEGACY_MASK);
-
- igb_update_interrupt_state(core);
+ igb_raise_interrupts(core, EIMS, val & mask);
}
static void mailbox_interrupt_to_vf(IGBCore *core, uint16_t vfn)
{
uint32_t ent = core->mac[VTIVAR_MISC + vfn];
+ uint32_t causes;
if ((ent & E1000_IVAR_VALID)) {
- core->mac[EICR] |= (ent & 0x3) << (22 - vfn * IGBVF_MSIX_VEC_NUM);
- igb_update_interrupt_state(core);
+ causes = (ent & 0x3) << (22 - vfn * IGBVF_MSIX_VEC_NUM);
+ igb_raise_interrupts(core, EICR, causes);
}
}
static void mailbox_interrupt_to_pf(IGBCore *core)
{
- igb_set_interrupt_cause(core, E1000_ICR_VMMB);
+ igb_raise_interrupts(core, ICR, E1000_ICR_VMMB);
}
static void igb_set_pfmailbox(IGBCore *core, int index, uint32_t val)
static void igb_set_eimc(IGBCore *core, int index, uint32_t val)
{
bool msix = !!(core->mac[GPIE] & E1000_GPIE_MSIX_MODE);
+ uint32_t mask = msix ? E1000_EICR_MSIX_MASK : E1000_EICR_LEGACY_MASK;
- /* Interrupts are disabled via a write to EIMC and reflected in EIMS. */
- core->mac[EIMS] &=
- ~(val & (msix ? E1000_EICR_MSIX_MASK : E1000_EICR_LEGACY_MASK));
+ trace_igb_irq_write_eimc(val, msix);
- trace_igb_irq_write_eimc(val, core->mac[EIMS], msix);
- igb_update_interrupt_state(core);
+ /* Interrupts are disabled via a write to EIMC and reflected in EIMS. */
+ igb_lower_interrupts(core, EIMS, val & mask);
}
static void igb_set_eiac(IGBCore *core, int index, uint32_t val)
* TODO: In IOV mode, only bit zero of this vector is available for the PF
* function.
*/
- core->mac[EICR] &=
- ~(val & (msix ? E1000_EICR_MSIX_MASK : E1000_EICR_LEGACY_MASK));
+ uint32_t mask = msix ? E1000_EICR_MSIX_MASK : E1000_EICR_LEGACY_MASK;
trace_igb_irq_write_eicr(val, msix);
- igb_update_interrupt_state(core);
+ igb_lower_interrupts(core, EICR, val & mask);
}
static void igb_set_vtctrl(IGBCore *core, int index, uint32_t val)
igb_update_flowctl_status(core);
/* signal link status change to the guest */
- igb_set_interrupt_cause(core, E1000_ICR_LSC);
+ igb_raise_interrupts(core, ICR, E1000_ICR_LSC);
}
}
core->mac[MDIC] = val | E1000_MDIC_READY;
if (val & E1000_MDIC_INT_EN) {
- igb_set_interrupt_cause(core, E1000_ICR_MDAC);
+ igb_raise_interrupts(core, ICR, E1000_ICR_MDAC);
}
}
igb_set_ics(IGBCore *core, int index, uint32_t val)
{
trace_e1000e_irq_write_ics(val);
- igb_set_interrupt_cause(core, val);
+ igb_raise_interrupts(core, ICR, val);
}
static void
igb_set_imc(IGBCore *core, int index, uint32_t val)
{
trace_e1000e_irq_ims_clear_set_imc(val);
- igb_clear_ims_bits(core, val);
- igb_update_interrupt_state(core);
+ igb_lower_interrupts(core, IMS, val);
}
static void
igb_set_ims(IGBCore *core, int index, uint32_t val)
{
- uint32_t valid_val = val & 0x77D4FBFD;
-
- trace_e1000e_irq_set_ims(val, core->mac[IMS], core->mac[IMS] | valid_val);
- core->mac[IMS] |= valid_val;
- igb_update_interrupt_state(core);
+ igb_raise_interrupts(core, IMS, val & 0x77D4FBFD);
}
-static void igb_commit_icr(IGBCore *core)
+static void igb_nsicr(IGBCore *core)
{
/*
* If GPIE.NSICR = 0, then the clear of IMS will occur only if at
*/
if ((core->mac[GPIE] & E1000_GPIE_NSICR) ||
(core->mac[IMS] && (core->mac[ICR] & E1000_ICR_INT_ASSERTED))) {
- igb_clear_ims_bits(core, core->mac[IAM]);
+ igb_lower_interrupts(core, IMS, core->mac[IAM]);
}
-
- igb_update_interrupt_state(core);
}
static void igb_set_icr(IGBCore *core, int index, uint32_t val)
{
- uint32_t icr = core->mac[ICR] & ~val;
-
- trace_igb_irq_icr_write(val, core->mac[ICR], icr);
- core->mac[ICR] = icr;
- igb_commit_icr(core);
+ igb_nsicr(core);
+ igb_lower_interrupts(core, ICR, val);
}
static uint32_t
igb_mac_icr_read(IGBCore *core, int index)
{
uint32_t ret = core->mac[ICR];
- trace_e1000e_irq_icr_read_entry(ret);
if (core->mac[GPIE] & E1000_GPIE_NSICR) {
trace_igb_irq_icr_clear_gpie_nsicr();
- core->mac[ICR] = 0;
+ igb_lower_interrupts(core, ICR, 0xffffffff);
} else if (core->mac[IMS] == 0) {
trace_e1000e_irq_icr_clear_zero_ims();
- core->mac[ICR] = 0;
+ igb_lower_interrupts(core, ICR, 0xffffffff);
} else if (!msix_enabled(core->owner)) {
trace_e1000e_irq_icr_clear_nonmsix_icr_read();
- core->mac[ICR] = 0;
+ igb_lower_interrupts(core, ICR, 0xffffffff);
}
- trace_e1000e_irq_icr_read_exit(core->mac[ICR]);
- igb_commit_icr(core);
+ igb_nsicr(core);
return ret;
}
e1000e_irq_postponed_by_xitr(uint32_t reg) "Interrupt postponed by [E]ITR register 0x%x"
e1000e_irq_clear(uint32_t offset, uint32_t old, uint32_t new) "Clearing interrupt register 0x%x: 0x%x --> 0x%x"
e1000e_irq_set(uint32_t offset, uint32_t old, uint32_t new) "Setting interrupt register 0x%x: 0x%x --> 0x%x"
-e1000e_irq_clear_ims(uint32_t bits, uint32_t old_ims, uint32_t new_ims) "Clearing IMS bits 0x%x: 0x%x --> 0x%x"
-e1000e_irq_set_ims(uint32_t bits, uint32_t old_ims, uint32_t new_ims) "Setting IMS bits 0x%x: 0x%x --> 0x%x"
e1000e_irq_fix_icr_asserted(uint32_t new_val) "ICR_ASSERTED bit fixed: 0x%x"
e1000e_irq_add_msi_other(uint32_t new_val) "ICR_OTHER bit added: 0x%x"
e1000e_irq_pending_interrupts(uint32_t pending, uint32_t icr, uint32_t ims) "ICR PENDING: 0x%x (ICR: 0x%x, IMS: 0x%x)"
-e1000e_irq_set_cause_entry(uint32_t val, uint32_t icr) "Going to set IRQ cause 0x%x, ICR: 0x%x"
-e1000e_irq_set_cause_exit(uint32_t val, uint32_t icr) "Set IRQ cause 0x%x, ICR: 0x%x"
-e1000e_irq_icr_write(uint32_t bits, uint32_t old_icr, uint32_t new_icr) "Clearing ICR bits 0x%x: 0x%x --> 0x%x"
e1000e_irq_write_ics(uint32_t val) "Adding ICR bits 0x%x"
e1000e_irq_icr_process_iame(void) "Clearing IMS bits due to IAME"
e1000e_irq_read_ics(uint32_t ics) "Current ICS: 0x%x"
e1000e_irq_read_ims(uint32_t ims) "Current IMS: 0x%x"
e1000e_irq_icr_clear_nonmsix_icr_read(void) "Clearing ICR on read due to non MSI-X int"
-e1000e_irq_icr_read_entry(uint32_t icr) "Starting ICR read. Current ICR: 0x%x"
-e1000e_irq_icr_read_exit(uint32_t icr) "Ending ICR read. Current ICR: 0x%x"
e1000e_irq_icr_clear_zero_ims(void) "Clearing ICR on read due to zero IMS"
e1000e_irq_icr_clear_iame(void) "Clearing ICR on read due to IAME"
e1000e_irq_iam_clear_eiame(uint32_t iam, uint32_t cause) "Clearing IMS due to EIAME, IAM: 0x%X, cause: 0x%X"
e1000e_irq_eitr_set(uint32_t eitr_num, uint32_t val) "EITR[%u] = %u"
e1000e_irq_itr_set(uint32_t val) "ITR = %u"
e1000e_irq_fire_all_timers(uint32_t val) "Firing all delay/throttling timers on all interrupts enable (0x%X written to IMS)"
-e1000e_irq_adding_delayed_causes(uint32_t val, uint32_t icr) "Merging delayed causes 0x%X to ICR 0x%X"
e1000e_irq_msix_pending_clearing(uint32_t cause, uint32_t int_cfg, uint32_t vec) "Clearing MSI-X pending bit for cause 0x%x, IVAR config 0x%x, vector %u"
e1000e_wrn_msix_vec_wrong(uint32_t cause, uint32_t cfg) "Invalid configuration for cause 0x%x: 0x%x"
igb_rx_metadata_rss(uint32_t rss) "RSS data: 0x%X"
igb_irq_icr_clear_gpie_nsicr(void) "Clearing ICR on read due to GPIE.NSICR enabled"
-igb_irq_icr_write(uint32_t bits, uint32_t old_icr, uint32_t new_icr) "Clearing ICR bits 0x%x: 0x%x --> 0x%x"
igb_irq_set_iam(uint32_t icr) "Update IAM: 0x%x"
igb_irq_read_iam(uint32_t icr) "Current IAM: 0x%x"
igb_irq_write_eics(uint32_t val, bool msix) "Update EICS: 0x%x MSI-X: %d"
igb_irq_write_eims(uint32_t val, bool msix) "Update EIMS: 0x%x MSI-X: %d"
-igb_irq_write_eimc(uint32_t val, uint32_t eims, bool msix) "Update EIMC: 0x%x EIMS: 0x%x MSI-X: %d"
+igb_irq_write_eimc(uint32_t val, bool msix) "Update EIMC: 0x%x MSI-X: %d"
igb_irq_write_eiac(uint32_t val) "Update EIAC: 0x%x"
igb_irq_write_eiam(uint32_t val, bool msix) "Update EIAM: 0x%x MSI-X: %d"
igb_irq_write_eicr(uint32_t val, bool msix) "Update EICR: 0x%x MSI-X: %d"