xref: /illumos-gate/usr/src/uts/common/io/ena/ena_intr.c (revision c46e4de3)
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