1da5577f0SRobert Mustacchi /* 2da5577f0SRobert Mustacchi * This file and its contents are supplied under the terms of the 3da5577f0SRobert Mustacchi * Common Development and Distribution License ("CDDL"), version 1.0. 4da5577f0SRobert Mustacchi * You may only use this file in accordance with the terms of version 5da5577f0SRobert Mustacchi * 1.0 of the CDDL. 6da5577f0SRobert Mustacchi * 7da5577f0SRobert Mustacchi * A full copy of the text of the CDDL should have accompanied this 8da5577f0SRobert Mustacchi * source. A copy of the CDDL is also available via the Internet at 9da5577f0SRobert Mustacchi * http://www.illumos.org/license/CDDL. 10da5577f0SRobert Mustacchi */ 11da5577f0SRobert Mustacchi 12da5577f0SRobert Mustacchi /* 13*c4a685adSRobert Mustacchi * Copyright 2019 Joyent, Inc. 1405768666SPaul Winder * Copyright 2017 Tegile Systems, Inc. All rights reserved. 15da5577f0SRobert Mustacchi */ 16da5577f0SRobert Mustacchi 17da5577f0SRobert Mustacchi /* 18da5577f0SRobert Mustacchi * ------------------------- 19da5577f0SRobert Mustacchi * Interrupt Handling Theory 20da5577f0SRobert Mustacchi * ------------------------- 21da5577f0SRobert Mustacchi * 22da5577f0SRobert Mustacchi * There are a couple different sets of interrupts that we need to worry about: 23da5577f0SRobert Mustacchi * 24da5577f0SRobert Mustacchi * - Interrupts from receive queues 25da5577f0SRobert Mustacchi * - Interrupts from transmit queues 26da5577f0SRobert Mustacchi * - 'Other Interrupts', such as the administrative queue 27da5577f0SRobert Mustacchi * 28da5577f0SRobert Mustacchi * 'Other Interrupts' are asynchronous events such as a link status change event 29da5577f0SRobert Mustacchi * being posted to the administrative queue, unrecoverable ECC errors, and more. 30da5577f0SRobert Mustacchi * If we have something being posted to the administrative queue, then we go 31da5577f0SRobert Mustacchi * through and process it, because it's generally enabled as a separate logical 32da5577f0SRobert Mustacchi * interrupt. Note, we may need to do more here eventually. To re-enable the 33da5577f0SRobert Mustacchi * interrupts from the 'Other Interrupts' section, we need to clear the PBA and 34da5577f0SRobert Mustacchi * write ENA to PFINT_ICR0. 35da5577f0SRobert Mustacchi * 36da5577f0SRobert Mustacchi * Interrupts from the transmit and receive queues indicates that our requests 37da5577f0SRobert Mustacchi * have been processed. In the rx case, it means that we have data that we 38da5577f0SRobert Mustacchi * should take a look at and send up the stack. In the tx case, it means that 39da5577f0SRobert Mustacchi * data which we got from MAC has now been sent out on the wire and we can free 40da5577f0SRobert Mustacchi * the associated data. Most of the logic for acting upon the presence of this 41da5577f0SRobert Mustacchi * data can be found in i40e_transciever.c which handles all of the DMA, rx, and 42da5577f0SRobert Mustacchi * tx operations. This file is dedicated to handling and dealing with interrupt 43da5577f0SRobert Mustacchi * processing. 44da5577f0SRobert Mustacchi * 45da5577f0SRobert Mustacchi * All devices supported by this driver support three kinds of interrupts: 46da5577f0SRobert Mustacchi * 47da5577f0SRobert Mustacchi * o Extended Message Signaled Interrupts (MSI-X) 48da5577f0SRobert Mustacchi * o Message Signaled Interrupts (MSI) 49da5577f0SRobert Mustacchi * o Legacy PCI interrupts (INTx) 50da5577f0SRobert Mustacchi * 51da5577f0SRobert Mustacchi * Generally speaking the hardware logically handles MSI and INTx the same and 52da5577f0SRobert Mustacchi * restricts us to only using a single interrupt, which isn't the interesting 53da5577f0SRobert Mustacchi * case. With MSI-X available, each physical function of the device provides the 54da5577f0SRobert Mustacchi * opportunity for multiple interrupts which is what we'll focus on. 55da5577f0SRobert Mustacchi * 56da5577f0SRobert Mustacchi * -------------------- 57da5577f0SRobert Mustacchi * Interrupt Management 58da5577f0SRobert Mustacchi * -------------------- 59da5577f0SRobert Mustacchi * 60da5577f0SRobert Mustacchi * By default, the admin queue, which consists of the asynchronous other 61da5577f0SRobert Mustacchi * interrupts is always bound to MSI-X vector zero. Next, we spread out all of 62da5577f0SRobert Mustacchi * the other interrupts that we have available to us over the remaining 63da5577f0SRobert Mustacchi * interrupt vectors. 64da5577f0SRobert Mustacchi * 65da5577f0SRobert Mustacchi * This means that there may be multiple queues, both tx and rx, which are 66da5577f0SRobert Mustacchi * mapped to the same interrupt. When the interrupt fires, we'll have to check 67da5577f0SRobert Mustacchi * all of them for servicing, before we go through and indicate that the 68da5577f0SRobert Mustacchi * interrupt is claimed. 69da5577f0SRobert Mustacchi * 70da5577f0SRobert Mustacchi * The hardware provides the means of mapping various queues to MSI-X interrupts 71da5577f0SRobert Mustacchi * by programming the I40E_QINT_RQCTL() and I4OE_QINT_TQCTL() registers. These 72da5577f0SRobert Mustacchi * registers can also be used to enable and disable whether or not the queue is 73da5577f0SRobert Mustacchi * a source of interrupts. As part of this, the hardware requires that we 74da5577f0SRobert Mustacchi * maintain a linked list of queues for each interrupt vector. While it may seem 75da5577f0SRobert Mustacchi * like this is only there for the purproses of ITRs, that's not the case. The 76da5577f0SRobert Mustacchi * first queue must be programmed in I40E_QINT_LNKLSTN(%vector) register. Each 77da5577f0SRobert Mustacchi * queue defines the next one in either the I40E_QINT_RQCTL or I40E_QINT_TQCTL 78da5577f0SRobert Mustacchi * register. 79da5577f0SRobert Mustacchi * 80da5577f0SRobert Mustacchi * Finally, the individual interrupt vector itself has the ability to be enabled 81da5577f0SRobert Mustacchi * and disabled. The overall interrupt is controlled through the 82da5577f0SRobert Mustacchi * I40E_PFINT_DYN_CTLN() register. This is used to turn on and off the interrupt 83da5577f0SRobert Mustacchi * as a whole. 84da5577f0SRobert Mustacchi * 85da5577f0SRobert Mustacchi * Note that this means that both the individual queue and the interrupt as a 86da5577f0SRobert Mustacchi * whole can be toggled and re-enabled. 87da5577f0SRobert Mustacchi * 88da5577f0SRobert Mustacchi * ------------------- 89da5577f0SRobert Mustacchi * Non-MSIX Management 90da5577f0SRobert Mustacchi * ------------------- 91da5577f0SRobert Mustacchi * 92da5577f0SRobert Mustacchi * We may have a case where the Operating System is unable to actually allocate 93da5577f0SRobert Mustacchi * any MSI-X to the system. In such a world, there is only one transmit/receive 94da5577f0SRobert Mustacchi * queue pair and it is bound to the same interrupt with index zero. The 95da5577f0SRobert Mustacchi * hardware doesn't allow us access to additional interrupt vectors in these 96da5577f0SRobert Mustacchi * modes. Note that technically we could support more transmit/receive queues if 97da5577f0SRobert Mustacchi * we wanted. 98da5577f0SRobert Mustacchi * 99da5577f0SRobert Mustacchi * In this world, because the interrupts for the admin queue and traffic are 100da5577f0SRobert Mustacchi * mixed together, we have to consult ICR0 to determine what has occurred. The 101da5577f0SRobert Mustacchi * QINT_TQCTL and QINT_RQCTL registers have a field, 'MSI-X 0 index' which 102da5577f0SRobert Mustacchi * allows us to set a specific bit in ICR0. There are up to seven such bits; 103da5577f0SRobert Mustacchi * however, we only use the bit 0 and 1 for the rx and tx queue respectively. 104da5577f0SRobert Mustacchi * These are contained by the I40E_INTR_NOTX_{R|T}X_QUEUE and 105da5577f0SRobert Mustacchi * I40E_INTR_NOTX_{R|T}X_MASK registers respectively. 106da5577f0SRobert Mustacchi * 107da5577f0SRobert Mustacchi * Unfortunately, these corresponding queue bits have no corresponding entry in 108da5577f0SRobert Mustacchi * the ICR0_ENA register. So instead, when enabling interrupts on the queues, we 109da5577f0SRobert Mustacchi * end up enabling it on the queue registers rather than on the MSI-X registers. 110da5577f0SRobert Mustacchi * In the MSI-X world, because they can be enabled and disabled, this is 111da5577f0SRobert Mustacchi * different and the queues can always be enabled and disabled, but the 112da5577f0SRobert Mustacchi * interrupts themselves are toggled (ignoring the question of interrupt 113da5577f0SRobert Mustacchi * blanking for polling on rings). 114da5577f0SRobert Mustacchi * 115da5577f0SRobert Mustacchi * Finally, we still have to set up the interrupt linked list, but the list is 116da5577f0SRobert Mustacchi * instead rooted at the register I40E_PFINT_LNKLST0, rather than being tied to 117da5577f0SRobert Mustacchi * one of the other MSI-X registers. 118da5577f0SRobert Mustacchi * 119da5577f0SRobert Mustacchi * -------------------- 120da5577f0SRobert Mustacchi * Interrupt Moderation 121da5577f0SRobert Mustacchi * -------------------- 122da5577f0SRobert Mustacchi * 123da5577f0SRobert Mustacchi * The XL710 hardware has three different interrupt moderation registers per 124da5577f0SRobert Mustacchi * interrupt. Unsurprisingly, we use these for: 125da5577f0SRobert Mustacchi * 126da5577f0SRobert Mustacchi * o RX interrupts 127da5577f0SRobert Mustacchi * o TX interrupts 128da5577f0SRobert Mustacchi * o 'Other interrupts' (link status change, admin queue, etc.) 129da5577f0SRobert Mustacchi * 130da5577f0SRobert Mustacchi * By default, we throttle 'other interrupts' the most, then TX interrupts, and 131da5577f0SRobert Mustacchi * then RX interrupts. The default values for these were based on trying to 132da5577f0SRobert Mustacchi * reason about both the importance and frequency of events. Generally speaking 133da5577f0SRobert Mustacchi * 'other interrupts' are not very frequent and they're not important for the 134da5577f0SRobert Mustacchi * I/O data path in and of itself (though they may indicate issues with the I/O 135da5577f0SRobert Mustacchi * data path). 136da5577f0SRobert Mustacchi * 137da5577f0SRobert Mustacchi * On the flip side, when we're not polling, RX interrupts are very important. 138da5577f0SRobert Mustacchi * The longer we wait for them, the more latency that we inject into the system. 139da5577f0SRobert Mustacchi * However, if we allow interrupts to occur too frequently, we risk a few 140da5577f0SRobert Mustacchi * problems: 141da5577f0SRobert Mustacchi * 142da5577f0SRobert Mustacchi * 1) Abusing system resources. Without proper interrupt blanking and polling, 143da5577f0SRobert Mustacchi * we can see upwards of 200k-300k interrupts per second on the system. 144da5577f0SRobert Mustacchi * 145da5577f0SRobert Mustacchi * 2) Not enough data coalescing to enable polling. In other words, the more 146da5577f0SRobert Mustacchi * data that we allow to build up, the more likely we'll be able to enable 147da5577f0SRobert Mustacchi * polling mode and allowing us to better handle bulk data. 148da5577f0SRobert Mustacchi * 149da5577f0SRobert Mustacchi * In-between the 'other interrupts' and the TX interrupts we have the 150da5577f0SRobert Mustacchi * reclamation of TX buffers. This operation is not quite as important as we 151da5577f0SRobert Mustacchi * generally size the ring large enough that we should be able to reclaim a 152da5577f0SRobert Mustacchi * substantial amount of the descriptors that we have used per interrupt. So 153da5577f0SRobert Mustacchi * while it's important that this interrupt occur, we don't necessarily need it 154da5577f0SRobert Mustacchi * firing as frequently as RX; it doesn't, on its own, induce additional latency 155da5577f0SRobert Mustacchi * into the system. 156da5577f0SRobert Mustacchi * 157da5577f0SRobert Mustacchi * Based on all this we currently assign static ITR values for the system. While 158da5577f0SRobert Mustacchi * we could move to a dynamic system (the hardware supports that), we'd want to 159da5577f0SRobert Mustacchi * make sure that we're seeing problems from this that we believe would be 160da5577f0SRobert Mustacchi * generally helped by the added complexity. 161da5577f0SRobert Mustacchi * 162da5577f0SRobert Mustacchi * Based on this, the default values that we have allow for the following 163da5577f0SRobert Mustacchi * interrupt thresholds: 164da5577f0SRobert Mustacchi * 165da5577f0SRobert Mustacchi * o 20k interrupts/s for RX 166da5577f0SRobert Mustacchi * o 5k interrupts/s for TX 167da5577f0SRobert Mustacchi * o 2k interupts/s for 'Other Interrupts' 168da5577f0SRobert Mustacchi */ 169da5577f0SRobert Mustacchi 170da5577f0SRobert Mustacchi #include "i40e_sw.h" 171da5577f0SRobert Mustacchi 172da5577f0SRobert Mustacchi #define I40E_INTR_NOTX_QUEUE 0 173da5577f0SRobert Mustacchi #define I40E_INTR_NOTX_INTR 0 174da5577f0SRobert Mustacchi #define I40E_INTR_NOTX_RX_QUEUE 0 175da5577f0SRobert Mustacchi #define I40E_INTR_NOTX_RX_MASK (1 << I40E_PFINT_ICR0_QUEUE_0_SHIFT) 176da5577f0SRobert Mustacchi #define I40E_INTR_NOTX_TX_QUEUE 1 177da5577f0SRobert Mustacchi #define I40E_INTR_NOTX_TX_MASK (1 << I40E_PFINT_ICR0_QUEUE_1_SHIFT) 178da5577f0SRobert Mustacchi 179da5577f0SRobert Mustacchi void 180da5577f0SRobert Mustacchi i40e_intr_set_itr(i40e_t *i40e, i40e_itr_index_t itr, uint_t val) 181da5577f0SRobert Mustacchi { 182da5577f0SRobert Mustacchi int i; 183da5577f0SRobert Mustacchi i40e_hw_t *hw = &i40e->i40e_hw_space; 184da5577f0SRobert Mustacchi 185da5577f0SRobert Mustacchi VERIFY3U(val, <=, I40E_MAX_ITR); 186da5577f0SRobert Mustacchi VERIFY3U(itr, <, I40E_ITR_INDEX_NONE); 187da5577f0SRobert Mustacchi 188da5577f0SRobert Mustacchi /* 189da5577f0SRobert Mustacchi * No matter the interrupt mode, the ITR for other interrupts is always 190da5577f0SRobert Mustacchi * on interrupt zero and the same is true if we're not using MSI-X. 191da5577f0SRobert Mustacchi */ 192da5577f0SRobert Mustacchi if (itr == I40E_ITR_INDEX_OTHER || 193da5577f0SRobert Mustacchi i40e->i40e_intr_type != DDI_INTR_TYPE_MSIX) { 194da5577f0SRobert Mustacchi I40E_WRITE_REG(hw, I40E_PFINT_ITR0(itr), val); 195da5577f0SRobert Mustacchi return; 196da5577f0SRobert Mustacchi } 197da5577f0SRobert Mustacchi 19805768666SPaul Winder for (i = 0; i < i40e->i40e_num_trqpairs; i++) { 19905768666SPaul Winder I40E_WRITE_REG(hw, I40E_PFINT_ITRN(itr, i), val); 200da5577f0SRobert Mustacchi } 201da5577f0SRobert Mustacchi } 202da5577f0SRobert Mustacchi 203da5577f0SRobert Mustacchi /* 204da5577f0SRobert Mustacchi * Re-enable the adminq. Note that the adminq doesn't have a traditional queue 205da5577f0SRobert Mustacchi * associated with it from an interrupt perspective and just lives on ICR0. 206da5577f0SRobert Mustacchi * However when MSI-X interrupts are not being used, then this also enables and 207da5577f0SRobert Mustacchi * disables those interrupts. 208da5577f0SRobert Mustacchi */ 209da5577f0SRobert Mustacchi static void 210da5577f0SRobert Mustacchi i40e_intr_adminq_enable(i40e_t *i40e) 211da5577f0SRobert Mustacchi { 212da5577f0SRobert Mustacchi i40e_hw_t *hw = &i40e->i40e_hw_space; 213da5577f0SRobert Mustacchi uint32_t reg; 214da5577f0SRobert Mustacchi 215da5577f0SRobert Mustacchi reg = I40E_PFINT_DYN_CTL0_INTENA_MASK | 216da5577f0SRobert Mustacchi I40E_PFINT_DYN_CTL0_CLEARPBA_MASK | 217da5577f0SRobert Mustacchi (I40E_ITR_INDEX_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT); 218da5577f0SRobert Mustacchi I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTL0, reg); 219da5577f0SRobert Mustacchi i40e_flush(hw); 220da5577f0SRobert Mustacchi } 221da5577f0SRobert Mustacchi 222da5577f0SRobert Mustacchi static void 223da5577f0SRobert Mustacchi i40e_intr_adminq_disable(i40e_t *i40e) 224da5577f0SRobert Mustacchi { 225da5577f0SRobert Mustacchi i40e_hw_t *hw = &i40e->i40e_hw_space; 226da5577f0SRobert Mustacchi uint32_t reg; 227da5577f0SRobert Mustacchi 228da5577f0SRobert Mustacchi reg = I40E_ITR_INDEX_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT; 229da5577f0SRobert Mustacchi I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTL0, reg); 230da5577f0SRobert Mustacchi } 231da5577f0SRobert Mustacchi 2328d5069bcSRyan Zezeski /* 2338d5069bcSRyan Zezeski * The next two functions enable/disable the reception of interrupts 2348d5069bcSRyan Zezeski * on the given vector. Only vectors 1..N are programmed by these 2358d5069bcSRyan Zezeski * functions; vector 0 is special and handled by a different register. 2368d5069bcSRyan Zezeski * We must subtract one from the vector because i40e implicitly adds 2378d5069bcSRyan Zezeski * one to the vector value. See section 10.2.2.10.13 for more details. 2388d5069bcSRyan Zezeski */ 239da5577f0SRobert Mustacchi static void 240da5577f0SRobert Mustacchi i40e_intr_io_enable(i40e_t *i40e, int vector) 241da5577f0SRobert Mustacchi { 242da5577f0SRobert Mustacchi uint32_t reg; 243da5577f0SRobert Mustacchi i40e_hw_t *hw = &i40e->i40e_hw_space; 244da5577f0SRobert Mustacchi 2458d5069bcSRyan Zezeski ASSERT3S(vector, >, 0); 246da5577f0SRobert Mustacchi reg = I40E_PFINT_DYN_CTLN_INTENA_MASK | 247da5577f0SRobert Mustacchi I40E_PFINT_DYN_CTLN_CLEARPBA_MASK | 248da5577f0SRobert Mustacchi (I40E_ITR_INDEX_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT); 249da5577f0SRobert Mustacchi I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTLN(vector - 1), reg); 250da5577f0SRobert Mustacchi } 251da5577f0SRobert Mustacchi 252da5577f0SRobert Mustacchi static void 253da5577f0SRobert Mustacchi i40e_intr_io_disable(i40e_t *i40e, int vector) 254da5577f0SRobert Mustacchi { 255da5577f0SRobert Mustacchi uint32_t reg; 256da5577f0SRobert Mustacchi i40e_hw_t *hw = &i40e->i40e_hw_space; 257da5577f0SRobert Mustacchi 2588d5069bcSRyan Zezeski ASSERT3S(vector, >, 0); 259da5577f0SRobert Mustacchi reg = I40E_ITR_INDEX_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT; 260da5577f0SRobert Mustacchi I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTLN(vector - 1), reg); 261da5577f0SRobert Mustacchi } 262da5577f0SRobert Mustacchi 263da5577f0SRobert Mustacchi /* 264da5577f0SRobert Mustacchi * When MSI-X interrupts are being used, then we can enable the actual 265da5577f0SRobert Mustacchi * interrupts themselves. However, when they are not, we instead have to turn 266da5577f0SRobert Mustacchi * towards the queue's CAUSE_ENA bit and enable that. 267da5577f0SRobert Mustacchi */ 268da5577f0SRobert Mustacchi void 269da5577f0SRobert Mustacchi i40e_intr_io_enable_all(i40e_t *i40e) 270da5577f0SRobert Mustacchi { 271da5577f0SRobert Mustacchi if (i40e->i40e_intr_type == DDI_INTR_TYPE_MSIX) { 272da5577f0SRobert Mustacchi int i; 273da5577f0SRobert Mustacchi 274da5577f0SRobert Mustacchi for (i = 1; i < i40e->i40e_intr_count; i++) { 275da5577f0SRobert Mustacchi i40e_intr_io_enable(i40e, i); 276da5577f0SRobert Mustacchi } 277da5577f0SRobert Mustacchi } else { 278da5577f0SRobert Mustacchi uint32_t reg; 279da5577f0SRobert Mustacchi i40e_hw_t *hw = &i40e->i40e_hw_space; 280da5577f0SRobert Mustacchi 281da5577f0SRobert Mustacchi reg = I40E_READ_REG(hw, I40E_QINT_RQCTL(I40E_INTR_NOTX_QUEUE)); 282da5577f0SRobert Mustacchi reg |= I40E_QINT_RQCTL_CAUSE_ENA_MASK; 283da5577f0SRobert Mustacchi I40E_WRITE_REG(hw, I40E_QINT_RQCTL(I40E_INTR_NOTX_QUEUE), reg); 284da5577f0SRobert Mustacchi 285da5577f0SRobert Mustacchi reg = I40E_READ_REG(hw, I40E_QINT_TQCTL(I40E_INTR_NOTX_QUEUE)); 286da5577f0SRobert Mustacchi reg |= I40E_QINT_TQCTL_CAUSE_ENA_MASK; 287da5577f0SRobert Mustacchi I40E_WRITE_REG(hw, I40E_QINT_TQCTL(I40E_INTR_NOTX_QUEUE), reg); 288da5577f0SRobert Mustacchi } 289da5577f0SRobert Mustacchi } 290da5577f0SRobert Mustacchi 291da5577f0SRobert Mustacchi /* 292da5577f0SRobert Mustacchi * When MSI-X interrupts are being used, then we can disable the actual 293da5577f0SRobert Mustacchi * interrupts themselves. However, when they are not, we instead have to turn 294da5577f0SRobert Mustacchi * towards the queue's CAUSE_ENA bit and disable that. 295da5577f0SRobert Mustacchi */ 296da5577f0SRobert Mustacchi void 297da5577f0SRobert Mustacchi i40e_intr_io_disable_all(i40e_t *i40e) 298da5577f0SRobert Mustacchi { 299da5577f0SRobert Mustacchi if (i40e->i40e_intr_type == DDI_INTR_TYPE_MSIX) { 300da5577f0SRobert Mustacchi int i; 301da5577f0SRobert Mustacchi 302da5577f0SRobert Mustacchi for (i = 1; i < i40e->i40e_intr_count; i++) { 303da5577f0SRobert Mustacchi i40e_intr_io_disable(i40e, i); 304da5577f0SRobert Mustacchi } 305da5577f0SRobert Mustacchi } else { 306da5577f0SRobert Mustacchi uint32_t reg; 307da5577f0SRobert Mustacchi i40e_hw_t *hw = &i40e->i40e_hw_space; 308da5577f0SRobert Mustacchi 309da5577f0SRobert Mustacchi reg = I40E_READ_REG(hw, I40E_QINT_RQCTL(I40E_INTR_NOTX_QUEUE)); 310da5577f0SRobert Mustacchi reg &= ~I40E_QINT_RQCTL_CAUSE_ENA_MASK; 311da5577f0SRobert Mustacchi I40E_WRITE_REG(hw, I40E_QINT_RQCTL(I40E_INTR_NOTX_QUEUE), reg); 312da5577f0SRobert Mustacchi 313da5577f0SRobert Mustacchi reg = I40E_READ_REG(hw, I40E_QINT_TQCTL(I40E_INTR_NOTX_QUEUE)); 314da5577f0SRobert Mustacchi reg &= ~I40E_QINT_TQCTL_CAUSE_ENA_MASK; 315da5577f0SRobert Mustacchi I40E_WRITE_REG(hw, I40E_QINT_TQCTL(I40E_INTR_NOTX_QUEUE), reg); 316da5577f0SRobert Mustacchi } 317da5577f0SRobert Mustacchi } 318da5577f0SRobert Mustacchi 319da5577f0SRobert Mustacchi /* 320da5577f0SRobert Mustacchi * As part of disabling the tx and rx queue's we're technically supposed to 321da5577f0SRobert Mustacchi * remove the linked list entries. The simplest way is to clear the LNKLSTN 322da5577f0SRobert Mustacchi * register by setting it to I40E_QUEUE_TYPE_EOL (0x7FF). 323da5577f0SRobert Mustacchi * 324da5577f0SRobert Mustacchi * Note all of the FM register access checks are performed by the caller. 325da5577f0SRobert Mustacchi */ 326da5577f0SRobert Mustacchi void 327da5577f0SRobert Mustacchi i40e_intr_io_clear_cause(i40e_t *i40e) 328da5577f0SRobert Mustacchi { 329*c4a685adSRobert Mustacchi uint32_t i; 330da5577f0SRobert Mustacchi i40e_hw_t *hw = &i40e->i40e_hw_space; 331da5577f0SRobert Mustacchi 332da5577f0SRobert Mustacchi if (i40e->i40e_intr_type != DDI_INTR_TYPE_MSIX) { 333da5577f0SRobert Mustacchi uint32_t reg; 334da5577f0SRobert Mustacchi reg = I40E_QUEUE_TYPE_EOL; 335da5577f0SRobert Mustacchi I40E_WRITE_REG(hw, I40E_PFINT_LNKLST0, reg); 336da5577f0SRobert Mustacchi return; 337da5577f0SRobert Mustacchi } 338da5577f0SRobert Mustacchi 339*c4a685adSRobert Mustacchi for (i = 0; i < i40e->i40e_intr_count - 1; i++) { 340da5577f0SRobert Mustacchi uint32_t reg; 341*c4a685adSRobert Mustacchi 342da5577f0SRobert Mustacchi reg = I40E_QUEUE_TYPE_EOL; 34305768666SPaul Winder I40E_WRITE_REG(hw, I40E_PFINT_LNKLSTN(i), reg); 344da5577f0SRobert Mustacchi } 345da5577f0SRobert Mustacchi 346da5577f0SRobert Mustacchi i40e_flush(hw); 347da5577f0SRobert Mustacchi } 348da5577f0SRobert Mustacchi 349da5577f0SRobert Mustacchi /* 350da5577f0SRobert Mustacchi * Finalize interrupt handling. Mostly this disables the admin queue. 351da5577f0SRobert Mustacchi */ 352da5577f0SRobert Mustacchi void 353da5577f0SRobert Mustacchi i40e_intr_chip_fini(i40e_t *i40e) 354da5577f0SRobert Mustacchi { 355da5577f0SRobert Mustacchi #ifdef DEBUG 356da5577f0SRobert Mustacchi int i; 357da5577f0SRobert Mustacchi uint32_t reg; 358da5577f0SRobert Mustacchi 359da5577f0SRobert Mustacchi i40e_hw_t *hw = &i40e->i40e_hw_space; 360da5577f0SRobert Mustacchi 361da5577f0SRobert Mustacchi /* 362da5577f0SRobert Mustacchi * Take a look and verify that all other interrupts have been disabled 363da5577f0SRobert Mustacchi * and the interrupt linked lists have been zeroed. 364da5577f0SRobert Mustacchi */ 365da5577f0SRobert Mustacchi if (i40e->i40e_intr_type == DDI_INTR_TYPE_MSIX) { 366*c4a685adSRobert Mustacchi for (i = 0; i < i40e->i40e_intr_count - 1; i++) { 36705768666SPaul Winder reg = I40E_READ_REG(hw, I40E_PFINT_DYN_CTLN(i)); 368da5577f0SRobert Mustacchi VERIFY0(reg & I40E_PFINT_DYN_CTLN_INTENA_MASK); 369da5577f0SRobert Mustacchi 37005768666SPaul Winder reg = I40E_READ_REG(hw, I40E_PFINT_LNKLSTN(i)); 371da5577f0SRobert Mustacchi VERIFY3U(reg, ==, I40E_QUEUE_TYPE_EOL); 372da5577f0SRobert Mustacchi } 373da5577f0SRobert Mustacchi } 374da5577f0SRobert Mustacchi #endif 375da5577f0SRobert Mustacchi 376da5577f0SRobert Mustacchi i40e_intr_adminq_disable(i40e); 377da5577f0SRobert Mustacchi } 378da5577f0SRobert Mustacchi 379da5577f0SRobert Mustacchi /* 3808d5069bcSRyan Zezeski * Set the head of the interrupt linked list. The PFINT_LNKLSTN[N] 3818d5069bcSRyan Zezeski * register actually refers to the 'N + 1' interrupt vector. E.g., 3828d5069bcSRyan Zezeski * PFINT_LNKLSTN[0] refers to interrupt vector 1. 3838d5069bcSRyan Zezeski */ 3848d5069bcSRyan Zezeski static void 3858d5069bcSRyan Zezeski i40e_set_lnklstn(i40e_t *i40e, uint_t vector, uint_t queue) 3868d5069bcSRyan Zezeski { 3878d5069bcSRyan Zezeski uint32_t reg; 3888d5069bcSRyan Zezeski i40e_hw_t *hw = &i40e->i40e_hw_space; 3898d5069bcSRyan Zezeski 3908d5069bcSRyan Zezeski reg = (queue << I40E_PFINT_LNKLSTN_FIRSTQ_INDX_SHIFT) | 3918d5069bcSRyan Zezeski (I40E_QUEUE_TYPE_RX << I40E_PFINT_LNKLSTN_FIRSTQ_TYPE_SHIFT); 3928d5069bcSRyan Zezeski 3938d5069bcSRyan Zezeski I40E_WRITE_REG(hw, I40E_PFINT_LNKLSTN(vector), reg); 3948d5069bcSRyan Zezeski DEBUGOUT2("PFINT_LNKLSTN[%u] = 0x%x", vector, reg); 3958d5069bcSRyan Zezeski } 3968d5069bcSRyan Zezeski 3978d5069bcSRyan Zezeski /* 3988d5069bcSRyan Zezeski * Set the QINT_RQCTL[queue] register. The next queue is always the Tx 3998d5069bcSRyan Zezeski * queue associated with this Rx queue. Unlike PFINT_LNKLSTN, the 4008d5069bcSRyan Zezeski * vector should be the actual vector this queue is on -- i.e., it 4018d5069bcSRyan Zezeski * should be equal to itrq_rx_intrvec. 4028d5069bcSRyan Zezeski */ 4038d5069bcSRyan Zezeski static void 4048d5069bcSRyan Zezeski i40e_set_rqctl(i40e_t *i40e, uint_t vector, uint_t queue) 4058d5069bcSRyan Zezeski { 4068d5069bcSRyan Zezeski uint32_t reg; 4078d5069bcSRyan Zezeski i40e_hw_t *hw = &i40e->i40e_hw_space; 4088d5069bcSRyan Zezeski 4098d5069bcSRyan Zezeski ASSERT3U(vector, ==, i40e->i40e_trqpairs[queue].itrq_rx_intrvec); 4108d5069bcSRyan Zezeski 4118d5069bcSRyan Zezeski reg = (vector << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) | 4128d5069bcSRyan Zezeski (I40E_ITR_INDEX_RX << I40E_QINT_RQCTL_ITR_INDX_SHIFT) | 4138d5069bcSRyan Zezeski (queue << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) | 4148d5069bcSRyan Zezeski (I40E_QUEUE_TYPE_TX << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT) | 4158d5069bcSRyan Zezeski I40E_QINT_RQCTL_CAUSE_ENA_MASK; 4168d5069bcSRyan Zezeski 4178d5069bcSRyan Zezeski I40E_WRITE_REG(hw, I40E_QINT_RQCTL(queue), reg); 4188d5069bcSRyan Zezeski DEBUGOUT2("QINT_RQCTL[%u] = 0x%x", queue, reg); 4198d5069bcSRyan Zezeski } 4208d5069bcSRyan Zezeski 4218d5069bcSRyan Zezeski /* 4228d5069bcSRyan Zezeski * Like i40e_set_rqctl(), but for QINT_TQCTL[queue]. The next queue is 4238d5069bcSRyan Zezeski * either the Rx queue of another TRQP, or EOL. 4248d5069bcSRyan Zezeski */ 4258d5069bcSRyan Zezeski static void 4268d5069bcSRyan Zezeski i40e_set_tqctl(i40e_t *i40e, uint_t vector, uint_t queue, uint_t next_queue) 4278d5069bcSRyan Zezeski { 4288d5069bcSRyan Zezeski uint32_t reg; 4298d5069bcSRyan Zezeski i40e_hw_t *hw = &i40e->i40e_hw_space; 4308d5069bcSRyan Zezeski 4318d5069bcSRyan Zezeski ASSERT3U(vector, ==, i40e->i40e_trqpairs[queue].itrq_tx_intrvec); 4328d5069bcSRyan Zezeski 4338d5069bcSRyan Zezeski reg = (vector << I40E_QINT_TQCTL_MSIX_INDX_SHIFT) | 4348d5069bcSRyan Zezeski (I40E_ITR_INDEX_TX << I40E_QINT_TQCTL_ITR_INDX_SHIFT) | 4358d5069bcSRyan Zezeski (next_queue << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT) | 4368d5069bcSRyan Zezeski (I40E_QUEUE_TYPE_RX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT) | 4378d5069bcSRyan Zezeski I40E_QINT_TQCTL_CAUSE_ENA_MASK; 4388d5069bcSRyan Zezeski 4398d5069bcSRyan Zezeski I40E_WRITE_REG(hw, I40E_QINT_TQCTL(queue), reg); 4408d5069bcSRyan Zezeski DEBUGOUT2("QINT_TQCTL[%u] = 0x%x", queue, reg); 4418d5069bcSRyan Zezeski } 4428d5069bcSRyan Zezeski 4438d5069bcSRyan Zezeski /* 4448d5069bcSRyan Zezeski * Program the interrupt linked list. Each vector has a linked list of 4458d5069bcSRyan Zezeski * queues which act as event sources for that vector. When one of 4468d5069bcSRyan Zezeski * those sources has an event the associated interrupt vector is 4478d5069bcSRyan Zezeski * fired. This mapping must match the mapping found in 4488d5069bcSRyan Zezeski * i40e_map_intrs_to_vectors(). 4498d5069bcSRyan Zezeski * 4508d5069bcSRyan Zezeski * See section 7.5.3 for more information about the configuration of 4518d5069bcSRyan Zezeski * the interrupt linked list. 452da5577f0SRobert Mustacchi */ 453da5577f0SRobert Mustacchi static void 454da5577f0SRobert Mustacchi i40e_intr_init_queue_msix(i40e_t *i40e) 455da5577f0SRobert Mustacchi { 4568d5069bcSRyan Zezeski uint_t intr_count; 457da5577f0SRobert Mustacchi 458da5577f0SRobert Mustacchi /* 4598d5069bcSRyan Zezeski * The 0th vector is for 'Other Interrupts' only (subject to 4608d5069bcSRyan Zezeski * change in the future). 461da5577f0SRobert Mustacchi */ 4628d5069bcSRyan Zezeski intr_count = i40e->i40e_intr_count - 1; 463da5577f0SRobert Mustacchi 4648d5069bcSRyan Zezeski for (uint_t vec = 0; vec < intr_count; vec++) { 4658d5069bcSRyan Zezeski boolean_t head = B_TRUE; 46605768666SPaul Winder 4678d5069bcSRyan Zezeski for (uint_t qidx = vec; qidx < i40e->i40e_num_trqpairs; 4688d5069bcSRyan Zezeski qidx += intr_count) { 4698d5069bcSRyan Zezeski uint_t next_qidx = qidx + intr_count; 470da5577f0SRobert Mustacchi 4718d5069bcSRyan Zezeski next_qidx = (next_qidx > i40e->i40e_num_trqpairs) ? 4728d5069bcSRyan Zezeski I40E_QUEUE_TYPE_EOL : next_qidx; 473da5577f0SRobert Mustacchi 4748d5069bcSRyan Zezeski if (head) { 4758d5069bcSRyan Zezeski i40e_set_lnklstn(i40e, vec, qidx); 4768d5069bcSRyan Zezeski head = B_FALSE; 47705768666SPaul Winder } 478da5577f0SRobert Mustacchi 4798d5069bcSRyan Zezeski i40e_set_rqctl(i40e, vec + 1, qidx); 4808d5069bcSRyan Zezeski i40e_set_tqctl(i40e, vec + 1, qidx, next_qidx); 4818d5069bcSRyan Zezeski } 4828d5069bcSRyan Zezeski } 483da5577f0SRobert Mustacchi } 484da5577f0SRobert Mustacchi 485da5577f0SRobert Mustacchi /* 486da5577f0SRobert Mustacchi * Set up a single queue to share the admin queue interrupt in the non-MSI-X 487da5577f0SRobert Mustacchi * world. Note we do not enable the queue as an interrupt cause at this time. We 488da5577f0SRobert Mustacchi * don't have any other vector of control here, unlike with the MSI-X interrupt 489da5577f0SRobert Mustacchi * case. 490da5577f0SRobert Mustacchi */ 491da5577f0SRobert Mustacchi static void 492da5577f0SRobert Mustacchi i40e_intr_init_queue_shared(i40e_t *i40e) 493da5577f0SRobert Mustacchi { 494da5577f0SRobert Mustacchi i40e_hw_t *hw = &i40e->i40e_hw_space; 495da5577f0SRobert Mustacchi uint32_t reg; 496da5577f0SRobert Mustacchi 497da5577f0SRobert Mustacchi VERIFY(i40e->i40e_intr_type == DDI_INTR_TYPE_FIXED || 498da5577f0SRobert Mustacchi i40e->i40e_intr_type == DDI_INTR_TYPE_MSI); 499da5577f0SRobert Mustacchi 500da5577f0SRobert Mustacchi reg = (I40E_INTR_NOTX_QUEUE << I40E_PFINT_LNKLST0_FIRSTQ_INDX_SHIFT) | 501da5577f0SRobert Mustacchi (I40E_QUEUE_TYPE_RX << I40E_PFINT_LNKLSTN_FIRSTQ_TYPE_SHIFT); 502da5577f0SRobert Mustacchi I40E_WRITE_REG(hw, I40E_PFINT_LNKLST0, reg); 503da5577f0SRobert Mustacchi 504da5577f0SRobert Mustacchi reg = (I40E_INTR_NOTX_INTR << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) | 505da5577f0SRobert Mustacchi (I40E_ITR_INDEX_RX << I40E_QINT_RQCTL_ITR_INDX_SHIFT) | 506da5577f0SRobert Mustacchi (I40E_INTR_NOTX_RX_QUEUE << I40E_QINT_RQCTL_MSIX0_INDX_SHIFT) | 507da5577f0SRobert Mustacchi (I40E_INTR_NOTX_QUEUE << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) | 508da5577f0SRobert Mustacchi (I40E_QUEUE_TYPE_TX << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT); 509da5577f0SRobert Mustacchi 510da5577f0SRobert Mustacchi I40E_WRITE_REG(hw, I40E_QINT_RQCTL(I40E_INTR_NOTX_QUEUE), reg); 511da5577f0SRobert Mustacchi 512da5577f0SRobert Mustacchi reg = (I40E_INTR_NOTX_INTR << I40E_QINT_TQCTL_MSIX_INDX_SHIFT) | 513da5577f0SRobert Mustacchi (I40E_ITR_INDEX_TX << I40E_QINT_TQCTL_ITR_INDX_SHIFT) | 514da5577f0SRobert Mustacchi (I40E_INTR_NOTX_TX_QUEUE << I40E_QINT_TQCTL_MSIX0_INDX_SHIFT) | 515da5577f0SRobert Mustacchi (I40E_QUEUE_TYPE_EOL << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT) | 516da5577f0SRobert Mustacchi (I40E_QUEUE_TYPE_RX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT); 517da5577f0SRobert Mustacchi 518da5577f0SRobert Mustacchi I40E_WRITE_REG(hw, I40E_QINT_TQCTL(I40E_INTR_NOTX_QUEUE), reg); 519da5577f0SRobert Mustacchi } 520da5577f0SRobert Mustacchi 521da5577f0SRobert Mustacchi /* 522da5577f0SRobert Mustacchi * Enable the specified queue as a valid source of interrupts. Note, this should 523da5577f0SRobert Mustacchi * only be used as part of the GLDv3's interrupt blanking routines. The debug 524da5577f0SRobert Mustacchi * build assertions are specific to that. 525da5577f0SRobert Mustacchi */ 526da5577f0SRobert Mustacchi void 5271b74b674SRobert Mustacchi i40e_intr_rx_queue_enable(i40e_trqpair_t *itrq) 528da5577f0SRobert Mustacchi { 529da5577f0SRobert Mustacchi uint32_t reg; 5301b74b674SRobert Mustacchi uint_t queue = itrq->itrq_index; 5311b74b674SRobert Mustacchi i40e_hw_t *hw = &itrq->itrq_i40e->i40e_hw_space; 532da5577f0SRobert Mustacchi 5331b74b674SRobert Mustacchi ASSERT(MUTEX_HELD(&itrq->itrq_rx_lock)); 5341b74b674SRobert Mustacchi ASSERT(queue < itrq->itrq_i40e->i40e_num_trqpairs); 535da5577f0SRobert Mustacchi 536da5577f0SRobert Mustacchi reg = I40E_READ_REG(hw, I40E_QINT_RQCTL(queue)); 537da5577f0SRobert Mustacchi ASSERT0(reg & I40E_QINT_RQCTL_CAUSE_ENA_MASK); 538da5577f0SRobert Mustacchi reg |= I40E_QINT_RQCTL_CAUSE_ENA_MASK; 539da5577f0SRobert Mustacchi I40E_WRITE_REG(hw, I40E_QINT_RQCTL(queue), reg); 540da5577f0SRobert Mustacchi } 541da5577f0SRobert Mustacchi 542da5577f0SRobert Mustacchi /* 543da5577f0SRobert Mustacchi * Disable the specified queue as a valid source of interrupts. Note, this 544da5577f0SRobert Mustacchi * should only be used as part of the GLDv3's interrupt blanking routines. The 545da5577f0SRobert Mustacchi * debug build assertions are specific to that. 546da5577f0SRobert Mustacchi */ 547da5577f0SRobert Mustacchi void 5481b74b674SRobert Mustacchi i40e_intr_rx_queue_disable(i40e_trqpair_t *itrq) 549da5577f0SRobert Mustacchi { 550da5577f0SRobert Mustacchi uint32_t reg; 5511b74b674SRobert Mustacchi uint_t queue = itrq->itrq_index; 5521b74b674SRobert Mustacchi i40e_hw_t *hw = &itrq->itrq_i40e->i40e_hw_space; 553da5577f0SRobert Mustacchi 5541b74b674SRobert Mustacchi ASSERT(MUTEX_HELD(&itrq->itrq_rx_lock)); 5551b74b674SRobert Mustacchi ASSERT(queue < itrq->itrq_i40e->i40e_num_trqpairs); 556da5577f0SRobert Mustacchi 557da5577f0SRobert Mustacchi reg = I40E_READ_REG(hw, I40E_QINT_RQCTL(queue)); 558da5577f0SRobert Mustacchi ASSERT3U(reg & I40E_QINT_RQCTL_CAUSE_ENA_MASK, ==, 559da5577f0SRobert Mustacchi I40E_QINT_RQCTL_CAUSE_ENA_MASK); 560da5577f0SRobert Mustacchi reg &= ~I40E_QINT_RQCTL_CAUSE_ENA_MASK; 561da5577f0SRobert Mustacchi I40E_WRITE_REG(hw, I40E_QINT_RQCTL(queue), reg); 562da5577f0SRobert Mustacchi } 563da5577f0SRobert Mustacchi 564da5577f0SRobert Mustacchi /* 565da5577f0SRobert Mustacchi * Start up the various chip's interrupt handling. We not only configure the 566da5577f0SRobert Mustacchi * adminq here, but we also go through and configure all of the actual queues, 567da5577f0SRobert Mustacchi * the interrupt linked lists, and others. 568da5577f0SRobert Mustacchi */ 569da5577f0SRobert Mustacchi void 570da5577f0SRobert Mustacchi i40e_intr_chip_init(i40e_t *i40e) 571da5577f0SRobert Mustacchi { 572da5577f0SRobert Mustacchi i40e_hw_t *hw = &i40e->i40e_hw_space; 573da5577f0SRobert Mustacchi uint32_t reg; 574da5577f0SRobert Mustacchi 575da5577f0SRobert Mustacchi /* 576da5577f0SRobert Mustacchi * Ensure that all non adminq interrupts are disabled at the chip level. 577da5577f0SRobert Mustacchi */ 578da5577f0SRobert Mustacchi i40e_intr_io_disable_all(i40e); 579da5577f0SRobert Mustacchi 580da5577f0SRobert Mustacchi I40E_WRITE_REG(hw, I40E_PFINT_ICR0_ENA, 0); 581da5577f0SRobert Mustacchi (void) I40E_READ_REG(hw, I40E_PFINT_ICR0); 582da5577f0SRobert Mustacchi 583da5577f0SRobert Mustacchi /* 584da5577f0SRobert Mustacchi * Always enable all of the other-class interrupts to be on their own 585da5577f0SRobert Mustacchi * ITR. This only needs to be set on interrupt zero, which has its own 586da5577f0SRobert Mustacchi * special setting. 587da5577f0SRobert Mustacchi */ 588da5577f0SRobert Mustacchi reg = I40E_ITR_INDEX_OTHER << I40E_PFINT_STAT_CTL0_OTHER_ITR_INDX_SHIFT; 589da5577f0SRobert Mustacchi I40E_WRITE_REG(hw, I40E_PFINT_STAT_CTL0, reg); 590da5577f0SRobert Mustacchi 591da5577f0SRobert Mustacchi /* 592da5577f0SRobert Mustacchi * Enable interrupt types we expect to receive. At the moment, this 593da5577f0SRobert Mustacchi * is limited to the adminq; however, we'll want to review 11.2.2.9.22 594da5577f0SRobert Mustacchi * for more types here as we add support for detecting them, handling 595da5577f0SRobert Mustacchi * them, and resetting the device as appropriate. 596da5577f0SRobert Mustacchi */ 597da5577f0SRobert Mustacchi reg = I40E_PFINT_ICR0_ENA_ADMINQ_MASK; 598da5577f0SRobert Mustacchi I40E_WRITE_REG(hw, I40E_PFINT_ICR0_ENA, reg); 599da5577f0SRobert Mustacchi 600da5577f0SRobert Mustacchi /* 601da5577f0SRobert Mustacchi * Always set the interrupt linked list to empty. We'll come back and 602da5577f0SRobert Mustacchi * change this if MSI-X are actually on the scene. 603da5577f0SRobert Mustacchi */ 604da5577f0SRobert Mustacchi I40E_WRITE_REG(hw, I40E_PFINT_LNKLST0, I40E_QUEUE_TYPE_EOL); 605da5577f0SRobert Mustacchi 606da5577f0SRobert Mustacchi i40e_intr_adminq_enable(i40e); 607da5577f0SRobert Mustacchi 608da5577f0SRobert Mustacchi /* 609da5577f0SRobert Mustacchi * Set up all of the queues and map them to interrupts based on the bit 610da5577f0SRobert Mustacchi * assignments. 611da5577f0SRobert Mustacchi */ 612da5577f0SRobert Mustacchi if (i40e->i40e_intr_type == DDI_INTR_TYPE_MSIX) { 613da5577f0SRobert Mustacchi i40e_intr_init_queue_msix(i40e); 614da5577f0SRobert Mustacchi } else { 615da5577f0SRobert Mustacchi i40e_intr_init_queue_shared(i40e); 616da5577f0SRobert Mustacchi } 617da5577f0SRobert Mustacchi 618da5577f0SRobert Mustacchi /* 619da5577f0SRobert Mustacchi * Finally set all of the default ITRs for the interrupts. Note that the 620da5577f0SRobert Mustacchi * queues will have been set up above. 621da5577f0SRobert Mustacchi */ 622da5577f0SRobert Mustacchi i40e_intr_set_itr(i40e, I40E_ITR_INDEX_RX, i40e->i40e_rx_itr); 623da5577f0SRobert Mustacchi i40e_intr_set_itr(i40e, I40E_ITR_INDEX_TX, i40e->i40e_tx_itr); 624da5577f0SRobert Mustacchi i40e_intr_set_itr(i40e, I40E_ITR_INDEX_OTHER, i40e->i40e_other_itr); 625da5577f0SRobert Mustacchi } 626da5577f0SRobert Mustacchi 627da5577f0SRobert Mustacchi static void 628da5577f0SRobert Mustacchi i40e_intr_adminq_work(i40e_t *i40e) 629da5577f0SRobert Mustacchi { 630da5577f0SRobert Mustacchi struct i40e_hw *hw = &i40e->i40e_hw_space; 631da5577f0SRobert Mustacchi struct i40e_arq_event_info evt; 632da5577f0SRobert Mustacchi uint16_t remain = 1; 633da5577f0SRobert Mustacchi 634da5577f0SRobert Mustacchi bzero(&evt, sizeof (struct i40e_arq_event_info)); 635da5577f0SRobert Mustacchi evt.buf_len = I40E_ADMINQ_BUFSZ; 636da5577f0SRobert Mustacchi evt.msg_buf = i40e->i40e_aqbuf; 637da5577f0SRobert Mustacchi 638da5577f0SRobert Mustacchi while (remain != 0) { 639da5577f0SRobert Mustacchi enum i40e_status_code ret; 640da5577f0SRobert Mustacchi uint16_t opcode; 641da5577f0SRobert Mustacchi 642da5577f0SRobert Mustacchi /* 643da5577f0SRobert Mustacchi * At the moment, the only error code that seems to be returned 644da5577f0SRobert Mustacchi * is one saying that there's no work. In such a case we leave 645da5577f0SRobert Mustacchi * this be. 646da5577f0SRobert Mustacchi */ 647da5577f0SRobert Mustacchi ret = i40e_clean_arq_element(hw, &evt, &remain); 648da5577f0SRobert Mustacchi if (ret != I40E_SUCCESS) 649da5577f0SRobert Mustacchi break; 650da5577f0SRobert Mustacchi 651da5577f0SRobert Mustacchi opcode = LE_16(evt.desc.opcode); 652da5577f0SRobert Mustacchi switch (opcode) { 653da5577f0SRobert Mustacchi case i40e_aqc_opc_get_link_status: 654da5577f0SRobert Mustacchi mutex_enter(&i40e->i40e_general_lock); 655da5577f0SRobert Mustacchi i40e_link_check(i40e); 656da5577f0SRobert Mustacchi mutex_exit(&i40e->i40e_general_lock); 657da5577f0SRobert Mustacchi break; 658da5577f0SRobert Mustacchi default: 659da5577f0SRobert Mustacchi /* 660da5577f0SRobert Mustacchi * Longer term we'll want to enable other causes here 661da5577f0SRobert Mustacchi * and get these cleaned up and doing something. 662da5577f0SRobert Mustacchi */ 663da5577f0SRobert Mustacchi break; 664da5577f0SRobert Mustacchi } 665da5577f0SRobert Mustacchi } 666da5577f0SRobert Mustacchi } 667da5577f0SRobert Mustacchi 668da5577f0SRobert Mustacchi static void 6698d5069bcSRyan Zezeski i40e_intr_rx_work(i40e_t *i40e, i40e_trqpair_t *itrq) 670da5577f0SRobert Mustacchi { 67105768666SPaul Winder mblk_t *mp = NULL; 672da5577f0SRobert Mustacchi 673da5577f0SRobert Mustacchi mutex_enter(&itrq->itrq_rx_lock); 67405768666SPaul Winder if (!itrq->itrq_intr_poll) 675da5577f0SRobert Mustacchi mp = i40e_ring_rx(itrq, I40E_POLL_NULL); 676da5577f0SRobert Mustacchi mutex_exit(&itrq->itrq_rx_lock); 677da5577f0SRobert Mustacchi 6788d5069bcSRyan Zezeski if (mp == NULL) 6798d5069bcSRyan Zezeski return; 6808d5069bcSRyan Zezeski 681da5577f0SRobert Mustacchi mac_rx_ring(i40e->i40e_mac_hdl, itrq->itrq_macrxring, mp, 682da5577f0SRobert Mustacchi itrq->itrq_rxgen); 683da5577f0SRobert Mustacchi } 684da5577f0SRobert Mustacchi 6858d5069bcSRyan Zezeski /* ARGSUSED */ 686da5577f0SRobert Mustacchi static void 6878d5069bcSRyan Zezeski i40e_intr_tx_work(i40e_t *i40e, i40e_trqpair_t *itrq) 688da5577f0SRobert Mustacchi { 689da5577f0SRobert Mustacchi i40e_tx_recycle_ring(itrq); 690da5577f0SRobert Mustacchi } 691da5577f0SRobert Mustacchi 692da5577f0SRobert Mustacchi /* 693da5577f0SRobert Mustacchi * At the moment, the only 'other' interrupt on ICR0 that we handle is the 694da5577f0SRobert Mustacchi * adminq. We should go through and support the other notifications at some 695da5577f0SRobert Mustacchi * point. 696da5577f0SRobert Mustacchi */ 697da5577f0SRobert Mustacchi static void 698da5577f0SRobert Mustacchi i40e_intr_other_work(i40e_t *i40e) 699da5577f0SRobert Mustacchi { 700da5577f0SRobert Mustacchi struct i40e_hw *hw = &i40e->i40e_hw_space; 701da5577f0SRobert Mustacchi uint32_t reg; 702da5577f0SRobert Mustacchi 703da5577f0SRobert Mustacchi reg = I40E_READ_REG(hw, I40E_PFINT_ICR0); 704da5577f0SRobert Mustacchi if (i40e_check_acc_handle(i40e->i40e_osdep_space.ios_reg_handle) != 705da5577f0SRobert Mustacchi DDI_FM_OK) { 706da5577f0SRobert Mustacchi ddi_fm_service_impact(i40e->i40e_dip, DDI_SERVICE_DEGRADED); 707da5577f0SRobert Mustacchi atomic_or_32(&i40e->i40e_state, I40E_ERROR); 708da5577f0SRobert Mustacchi return; 709da5577f0SRobert Mustacchi } 710da5577f0SRobert Mustacchi 711da5577f0SRobert Mustacchi if (reg & I40E_PFINT_ICR0_ADMINQ_MASK) 712da5577f0SRobert Mustacchi i40e_intr_adminq_work(i40e); 713da5577f0SRobert Mustacchi 714da5577f0SRobert Mustacchi /* 715da5577f0SRobert Mustacchi * Make sure that the adminq interrupt is not masked and then explicitly 716da5577f0SRobert Mustacchi * enable the adminq and thus the other interrupt. 717da5577f0SRobert Mustacchi */ 718da5577f0SRobert Mustacchi reg = I40E_READ_REG(hw, I40E_PFINT_ICR0_ENA); 719da5577f0SRobert Mustacchi reg |= I40E_PFINT_ICR0_ENA_ADMINQ_MASK; 720da5577f0SRobert Mustacchi I40E_WRITE_REG(hw, I40E_PFINT_ICR0_ENA, reg); 721da5577f0SRobert Mustacchi 722da5577f0SRobert Mustacchi i40e_intr_adminq_enable(i40e); 723da5577f0SRobert Mustacchi } 724da5577f0SRobert Mustacchi 7258d5069bcSRyan Zezeski /* 7268d5069bcSRyan Zezeski * Handle an MSI-X interrupt. See section 7.5.1.3 for an overview of 7278d5069bcSRyan Zezeski * the MSI-X interrupt sequence. 7288d5069bcSRyan Zezeski */ 729da5577f0SRobert Mustacchi uint_t 730da5577f0SRobert Mustacchi i40e_intr_msix(void *arg1, void *arg2) 731da5577f0SRobert Mustacchi { 732da5577f0SRobert Mustacchi i40e_t *i40e = (i40e_t *)arg1; 7338d5069bcSRyan Zezeski uint_t vector_idx = (uint_t)(uintptr_t)arg2; 7348d5069bcSRyan Zezeski 7358d5069bcSRyan Zezeski ASSERT3U(vector_idx, <, i40e->i40e_intr_count); 736da5577f0SRobert Mustacchi 737da5577f0SRobert Mustacchi /* 738da5577f0SRobert Mustacchi * When using MSI-X interrupts, vector 0 is always reserved for the 739da5577f0SRobert Mustacchi * adminq at this time. Though longer term, we'll want to also bridge 740da5577f0SRobert Mustacchi * some I/O to them. 741da5577f0SRobert Mustacchi */ 742da5577f0SRobert Mustacchi if (vector_idx == 0) { 743da5577f0SRobert Mustacchi i40e_intr_other_work(i40e); 744da5577f0SRobert Mustacchi return (DDI_INTR_CLAIMED); 745da5577f0SRobert Mustacchi } 746da5577f0SRobert Mustacchi 7478d5069bcSRyan Zezeski ASSERT3U(vector_idx, >, 0); 748da5577f0SRobert Mustacchi 7498d5069bcSRyan Zezeski /* 7508d5069bcSRyan Zezeski * We determine the queue indexes via simple arithmetic (as 7518d5069bcSRyan Zezeski * opposed to keeping explicit state like a bitmap). While 7528d5069bcSRyan Zezeski * conveinent, it does mean that i40e_map_intrs_to_vectors(), 7538d5069bcSRyan Zezeski * i40e_intr_init_queue_msix(), and this function must be 7548d5069bcSRyan Zezeski * modified as a unit. 7558d5069bcSRyan Zezeski * 7568d5069bcSRyan Zezeski * We subtract 1 from the vector to offset the addition we 7578d5069bcSRyan Zezeski * performed during i40e_map_intrs_to_vectors(). 7588d5069bcSRyan Zezeski */ 7598d5069bcSRyan Zezeski for (uint_t i = vector_idx - 1; i < i40e->i40e_num_trqpairs; 7608d5069bcSRyan Zezeski i += (i40e->i40e_intr_count - 1)) { 7618d5069bcSRyan Zezeski i40e_trqpair_t *itrq = &i40e->i40e_trqpairs[i]; 7628d5069bcSRyan Zezeski 7638d5069bcSRyan Zezeski ASSERT3U(i, <, i40e->i40e_num_trqpairs); 7648d5069bcSRyan Zezeski ASSERT3P(itrq, !=, NULL); 7658d5069bcSRyan Zezeski i40e_intr_rx_work(i40e, itrq); 7668d5069bcSRyan Zezeski i40e_intr_tx_work(i40e, itrq); 7678d5069bcSRyan Zezeski } 7688d5069bcSRyan Zezeski 7698d5069bcSRyan Zezeski i40e_intr_io_enable(i40e, vector_idx); 770da5577f0SRobert Mustacchi return (DDI_INTR_CLAIMED); 771da5577f0SRobert Mustacchi } 772da5577f0SRobert Mustacchi 773da5577f0SRobert Mustacchi static uint_t 774da5577f0SRobert Mustacchi i40e_intr_notx(i40e_t *i40e, boolean_t shared) 775da5577f0SRobert Mustacchi { 776da5577f0SRobert Mustacchi i40e_hw_t *hw = &i40e->i40e_hw_space; 777da5577f0SRobert Mustacchi uint32_t reg; 7788d5069bcSRyan Zezeski i40e_trqpair_t *itrq = &i40e->i40e_trqpairs[0]; 779da5577f0SRobert Mustacchi int ret = DDI_INTR_CLAIMED; 780da5577f0SRobert Mustacchi 781da5577f0SRobert Mustacchi if (shared == B_TRUE) { 782da5577f0SRobert Mustacchi mutex_enter(&i40e->i40e_general_lock); 783da5577f0SRobert Mustacchi if (i40e->i40e_state & I40E_SUSPENDED) { 784da5577f0SRobert Mustacchi mutex_exit(&i40e->i40e_general_lock); 785da5577f0SRobert Mustacchi return (DDI_INTR_UNCLAIMED); 786da5577f0SRobert Mustacchi } 787da5577f0SRobert Mustacchi mutex_exit(&i40e->i40e_general_lock); 788da5577f0SRobert Mustacchi } 789da5577f0SRobert Mustacchi 790da5577f0SRobert Mustacchi reg = I40E_READ_REG(hw, I40E_PFINT_ICR0); 791da5577f0SRobert Mustacchi if (i40e_check_acc_handle(i40e->i40e_osdep_space.ios_reg_handle) != 792da5577f0SRobert Mustacchi DDI_FM_OK) { 793da5577f0SRobert Mustacchi ddi_fm_service_impact(i40e->i40e_dip, DDI_SERVICE_DEGRADED); 794da5577f0SRobert Mustacchi atomic_or_32(&i40e->i40e_state, I40E_ERROR); 795da5577f0SRobert Mustacchi return (DDI_INTR_CLAIMED); 796da5577f0SRobert Mustacchi } 797da5577f0SRobert Mustacchi 798da5577f0SRobert Mustacchi if (reg == 0) { 799da5577f0SRobert Mustacchi if (shared == B_TRUE) 800da5577f0SRobert Mustacchi ret = DDI_INTR_UNCLAIMED; 801da5577f0SRobert Mustacchi goto done; 802da5577f0SRobert Mustacchi } 803da5577f0SRobert Mustacchi 804da5577f0SRobert Mustacchi if (reg & I40E_PFINT_ICR0_ADMINQ_MASK) 805da5577f0SRobert Mustacchi i40e_intr_adminq_work(i40e); 806da5577f0SRobert Mustacchi 807da5577f0SRobert Mustacchi if (reg & I40E_INTR_NOTX_RX_MASK) 8088d5069bcSRyan Zezeski i40e_intr_rx_work(i40e, itrq); 809da5577f0SRobert Mustacchi 810da5577f0SRobert Mustacchi if (reg & I40E_INTR_NOTX_TX_MASK) 8118d5069bcSRyan Zezeski i40e_intr_tx_work(i40e, itrq); 812da5577f0SRobert Mustacchi 813da5577f0SRobert Mustacchi done: 814da5577f0SRobert Mustacchi i40e_intr_adminq_enable(i40e); 815da5577f0SRobert Mustacchi return (ret); 816da5577f0SRobert Mustacchi 817da5577f0SRobert Mustacchi } 818da5577f0SRobert Mustacchi 819da5577f0SRobert Mustacchi /* ARGSUSED */ 820da5577f0SRobert Mustacchi uint_t 821da5577f0SRobert Mustacchi i40e_intr_msi(void *arg1, void *arg2) 822da5577f0SRobert Mustacchi { 823da5577f0SRobert Mustacchi i40e_t *i40e = (i40e_t *)arg1; 824da5577f0SRobert Mustacchi 825da5577f0SRobert Mustacchi return (i40e_intr_notx(i40e, B_FALSE)); 826da5577f0SRobert Mustacchi } 827da5577f0SRobert Mustacchi 828da5577f0SRobert Mustacchi /* ARGSUSED */ 829da5577f0SRobert Mustacchi uint_t 830da5577f0SRobert Mustacchi i40e_intr_legacy(void *arg1, void *arg2) 831da5577f0SRobert Mustacchi { 832da5577f0SRobert Mustacchi i40e_t *i40e = (i40e_t *)arg1; 833da5577f0SRobert Mustacchi 834da5577f0SRobert Mustacchi return (i40e_intr_notx(i40e, B_TRUE)); 835da5577f0SRobert Mustacchi } 836