16f443ebcSRyan Zezeski /*
26f443ebcSRyan Zezeski * This file and its contents are supplied under the terms of the
36f443ebcSRyan Zezeski * Common Development and Distribution License ("CDDL"), version 1.0.
46f443ebcSRyan Zezeski * You may only use this file in accordance with the terms of version
56f443ebcSRyan Zezeski * 1.0 of the CDDL.
66f443ebcSRyan Zezeski *
76f443ebcSRyan Zezeski * A full copy of the text of the CDDL should have accompanied this
86f443ebcSRyan Zezeski * source. A copy of the CDDL is also available via the Internet at
96f443ebcSRyan Zezeski * http://www.illumos.org/license/CDDL.
106f443ebcSRyan Zezeski */
116f443ebcSRyan Zezeski
126f443ebcSRyan Zezeski /*
13*c46e4de3SAndy Fiddaman * Copyright 2024 Oxide Computer Company
146f443ebcSRyan Zezeski */
15*c46e4de3SAndy Fiddaman
166f443ebcSRyan Zezeski #include "ena.h"
176f443ebcSRyan Zezeski
186f443ebcSRyan Zezeski /*
196f443ebcSRyan Zezeski * We currently limit the number of Tx/Rx queues to the number of
206f443ebcSRyan Zezeski * available interrupts (minus one for the admin queue).
216f443ebcSRyan Zezeski */
226f443ebcSRyan Zezeski static uint_t
ena_io_intr(caddr_t arg1,caddr_t arg2)236f443ebcSRyan Zezeski ena_io_intr(caddr_t arg1, caddr_t arg2)
246f443ebcSRyan Zezeski {
256f443ebcSRyan Zezeski ena_t *ena = (ena_t *)arg1;
266f443ebcSRyan Zezeski uint16_t vector = (uintptr_t)(void *)arg2;
276f443ebcSRyan Zezeski ASSERT3U(vector, >, 0);
286f443ebcSRyan Zezeski ASSERT3U(vector, <, ena->ena_num_intrs);
296f443ebcSRyan Zezeski ena_txq_t *txq = &ena->ena_txqs[vector - 1];
306f443ebcSRyan Zezeski ena_rxq_t *rxq = &ena->ena_rxqs[vector - 1];
316f443ebcSRyan Zezeski uint32_t intr_ctrl;
326f443ebcSRyan Zezeski
33*c46e4de3SAndy Fiddaman if ((ena->ena_state & ENA_STATE_STARTED) == 0)
34*c46e4de3SAndy Fiddaman return (DDI_INTR_CLAIMED);
35*c46e4de3SAndy Fiddaman
366f443ebcSRyan Zezeski ASSERT3P(txq, !=, NULL);
376f443ebcSRyan Zezeski ASSERT3P(rxq, !=, NULL);
386f443ebcSRyan Zezeski ena_tx_intr_work(txq);
396f443ebcSRyan Zezeski ena_rx_intr_work(rxq);
406f443ebcSRyan Zezeski
416f443ebcSRyan Zezeski /*
426f443ebcSRyan Zezeski * The Rx/Tx queue share the same interrupt, only need to
436f443ebcSRyan Zezeski * unmask interrupts for one of them.
446f443ebcSRyan Zezeski */
456f443ebcSRyan Zezeski intr_ctrl = ena_hw_abs_read32(ena, txq->et_cq_unmask_addr);
466f443ebcSRyan Zezeski ENAHW_REG_INTR_UNMASK(intr_ctrl);
476f443ebcSRyan Zezeski ena_hw_abs_write32(ena, txq->et_cq_unmask_addr, intr_ctrl);
486f443ebcSRyan Zezeski return (DDI_INTR_CLAIMED);
496f443ebcSRyan Zezeski }
506f443ebcSRyan Zezeski
516f443ebcSRyan Zezeski static uint_t
ena_admin_intr(caddr_t arg1,caddr_t arg2)526f443ebcSRyan Zezeski ena_admin_intr(caddr_t arg1, caddr_t arg2)
536f443ebcSRyan Zezeski {
546f443ebcSRyan Zezeski ena_t *ena = (ena_t *)arg1;
556f443ebcSRyan Zezeski
56*c46e4de3SAndy Fiddaman if ((ena->ena_state & ENA_STATE_STARTED) != 0)
57*c46e4de3SAndy Fiddaman ena_aenq_work(ena);
586f443ebcSRyan Zezeski return (DDI_INTR_CLAIMED);
596f443ebcSRyan Zezeski }
606f443ebcSRyan Zezeski
616f443ebcSRyan Zezeski void
ena_intr_remove_handlers(ena_t * ena,bool resetting)62*c46e4de3SAndy Fiddaman ena_intr_remove_handlers(ena_t *ena, bool resetting)
636f443ebcSRyan Zezeski {
64*c46e4de3SAndy Fiddaman VERIFY0(resetting);
65*c46e4de3SAndy Fiddaman
666f443ebcSRyan Zezeski for (int i = 0; i < ena->ena_num_intrs; i++) {
676f443ebcSRyan Zezeski int ret = ddi_intr_remove_handler(ena->ena_intr_handles[i]);
686f443ebcSRyan Zezeski
696f443ebcSRyan Zezeski /* Nothing we can really do except log. */
706f443ebcSRyan Zezeski if (ret != DDI_SUCCESS) {
716f443ebcSRyan Zezeski ena_err(ena, "failed to remove interrupt handler for "
726f443ebcSRyan Zezeski "vector %d: %d", i, ret);
736f443ebcSRyan Zezeski }
746f443ebcSRyan Zezeski }
756f443ebcSRyan Zezeski }
766f443ebcSRyan Zezeski
776f443ebcSRyan Zezeski /*
786f443ebcSRyan Zezeski * The ena driver uses separate interrupt handlers for the admin queue
796f443ebcSRyan Zezeski * and I/O queues.
806f443ebcSRyan Zezeski */
81*c46e4de3SAndy Fiddaman bool
ena_intr_add_handlers(ena_t * ena)826f443ebcSRyan Zezeski ena_intr_add_handlers(ena_t *ena)
836f443ebcSRyan Zezeski {
846f443ebcSRyan Zezeski ASSERT3S(ena->ena_num_intrs, >=, 2);
856f443ebcSRyan Zezeski if (ddi_intr_add_handler(ena->ena_intr_handles[0], ena_admin_intr, ena,
866f443ebcSRyan Zezeski (void *)(uintptr_t)0) != DDI_SUCCESS) {
876f443ebcSRyan Zezeski ena_err(ena, "failed to add admin interrupt handler");
88*c46e4de3SAndy Fiddaman return (false);
896f443ebcSRyan Zezeski }
906f443ebcSRyan Zezeski
916f443ebcSRyan Zezeski for (int i = 1; i < ena->ena_num_intrs; i++) {
926f443ebcSRyan Zezeski caddr_t vector = (void *)(uintptr_t)(i);
936f443ebcSRyan Zezeski int ret = ddi_intr_add_handler(ena->ena_intr_handles[i],
946f443ebcSRyan Zezeski ena_io_intr, ena, vector);
956f443ebcSRyan Zezeski
966f443ebcSRyan Zezeski if (ret != DDI_SUCCESS) {
976f443ebcSRyan Zezeski ena_err(ena, "failed to add I/O interrupt handler "
986f443ebcSRyan Zezeski "for vector %u", i);
996f443ebcSRyan Zezeski
1006f443ebcSRyan Zezeski /*
1016f443ebcSRyan Zezeski * If we fail to add any I/O handler, then all
1026f443ebcSRyan Zezeski * successfully added handlers are removed,
1036f443ebcSRyan Zezeski * including the admin handler. For example,
1046f443ebcSRyan Zezeski * when i=2 we remove handler 1 (the first I/O
1056f443ebcSRyan Zezeski * handler), and when i=1 we remove handler 0
1066f443ebcSRyan Zezeski * (the admin handler).
1076f443ebcSRyan Zezeski */
1086f443ebcSRyan Zezeski while (i >= 1) {
1096f443ebcSRyan Zezeski i--;
1106f443ebcSRyan Zezeski (void) ddi_intr_remove_handler(
1116f443ebcSRyan Zezeski ena->ena_intr_handles[i]);
1126f443ebcSRyan Zezeski }
1136f443ebcSRyan Zezeski
114*c46e4de3SAndy Fiddaman return (false);
1156f443ebcSRyan Zezeski }
1166f443ebcSRyan Zezeski }
1176f443ebcSRyan Zezeski
118*c46e4de3SAndy Fiddaman return (true);
1196f443ebcSRyan Zezeski }
1206f443ebcSRyan Zezeski
121*c46e4de3SAndy Fiddaman bool
ena_intrs_disable(ena_t * ena)1226f443ebcSRyan Zezeski ena_intrs_disable(ena_t *ena)
1236f443ebcSRyan Zezeski {
1246f443ebcSRyan Zezeski int ret;
1256f443ebcSRyan Zezeski
1266f443ebcSRyan Zezeski if (ena->ena_intr_caps & DDI_INTR_FLAG_BLOCK) {
1276f443ebcSRyan Zezeski if ((ret = ddi_intr_block_disable(ena->ena_intr_handles,
1286f443ebcSRyan Zezeski ena->ena_num_intrs)) != DDI_SUCCESS) {
1296f443ebcSRyan Zezeski ena_err(ena, "failed to block disable interrupts: %d",
1306f443ebcSRyan Zezeski ret);
131*c46e4de3SAndy Fiddaman return (false);
1326f443ebcSRyan Zezeski }
1336f443ebcSRyan Zezeski } else {
1346f443ebcSRyan Zezeski for (int i = 0; i < ena->ena_num_intrs; i++) {
1356f443ebcSRyan Zezeski ret = ddi_intr_disable(ena->ena_intr_handles[i]);
1366f443ebcSRyan Zezeski if (ret != DDI_SUCCESS) {
1376f443ebcSRyan Zezeski ena_err(ena, "failed to disable interrupt "
1386f443ebcSRyan Zezeski "%d: %d", i, ret);
139*c46e4de3SAndy Fiddaman return (false);
1406f443ebcSRyan Zezeski }
1416f443ebcSRyan Zezeski }
1426f443ebcSRyan Zezeski }
1436f443ebcSRyan Zezeski
144*c46e4de3SAndy Fiddaman return (true);
1456f443ebcSRyan Zezeski }
1466f443ebcSRyan Zezeski
147*c46e4de3SAndy Fiddaman bool
ena_intrs_enable(ena_t * ena)1486f443ebcSRyan Zezeski ena_intrs_enable(ena_t *ena)
1496f443ebcSRyan Zezeski {
1506f443ebcSRyan Zezeski int ret;
1516f443ebcSRyan Zezeski
1526f443ebcSRyan Zezeski if (ena->ena_intr_caps & DDI_INTR_FLAG_BLOCK) {
1536f443ebcSRyan Zezeski if ((ret = ddi_intr_block_enable(ena->ena_intr_handles,
1546f443ebcSRyan Zezeski ena->ena_num_intrs)) != DDI_SUCCESS) {
1556f443ebcSRyan Zezeski ena_err(ena, "failed to block enable interrupts: %d",
1566f443ebcSRyan Zezeski ret);
157*c46e4de3SAndy Fiddaman return (false);
1586f443ebcSRyan Zezeski }
1596f443ebcSRyan Zezeski } else {
1606f443ebcSRyan Zezeski for (int i = 0; i < ena->ena_num_intrs; i++) {
1616f443ebcSRyan Zezeski if ((ret = ddi_intr_enable(ena->ena_intr_handles[i])) !=
1626f443ebcSRyan Zezeski DDI_SUCCESS) {
1636f443ebcSRyan Zezeski ena_err(ena, "failed to enable interrupt "
1646f443ebcSRyan Zezeski "%d: %d", i, ret);
1656f443ebcSRyan Zezeski
1666f443ebcSRyan Zezeski /*
1676f443ebcSRyan Zezeski * If we fail to enable any interrupt,
1686f443ebcSRyan Zezeski * then all interrupts are disabled.
1696f443ebcSRyan Zezeski */
1706f443ebcSRyan Zezeski while (i >= 1) {
1716f443ebcSRyan Zezeski i--;
1726f443ebcSRyan Zezeski (void) ddi_intr_disable(
1736f443ebcSRyan Zezeski ena->ena_intr_handles[i]);
1746f443ebcSRyan Zezeski }
1756f443ebcSRyan Zezeski
176*c46e4de3SAndy Fiddaman return (false);
1776f443ebcSRyan Zezeski }
1786f443ebcSRyan Zezeski }
1796f443ebcSRyan Zezeski }
1806f443ebcSRyan Zezeski
181*c46e4de3SAndy Fiddaman return (true);
1826f443ebcSRyan Zezeski }
183