1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2015 - 2024 Beijing WangXun Technology Co., Ltd. */ 3 4 #include <linux/irqdomain.h> 5 #include <linux/pci.h> 6 7 #include "../libwx/wx_type.h" 8 #include "../libwx/wx_lib.h" 9 #include "../libwx/wx_hw.h" 10 #include "txgbe_type.h" 11 #include "txgbe_phy.h" 12 #include "txgbe_irq.h" 13 14 /** 15 * txgbe_irq_enable - Enable default interrupt generation settings 16 * @wx: pointer to private structure 17 * @queues: enable irqs for queues 18 **/ 19 void txgbe_irq_enable(struct wx *wx, bool queues) 20 { 21 wr32(wx, WX_PX_MISC_IEN, TXGBE_PX_MISC_IEN_MASK); 22 23 /* unmask interrupt */ 24 wx_intr_enable(wx, TXGBE_INTR_MISC); 25 if (queues) 26 wx_intr_enable(wx, TXGBE_INTR_QALL(wx)); 27 } 28 29 /** 30 * txgbe_request_queue_irqs - Initialize MSI-X queue interrupts 31 * @wx: board private structure 32 * 33 * Allocate MSI-X queue vectors and request interrupts from the kernel. 34 **/ 35 int txgbe_request_queue_irqs(struct wx *wx) 36 { 37 struct net_device *netdev = wx->netdev; 38 int vector, err; 39 40 if (!wx->pdev->msix_enabled) 41 return 0; 42 43 for (vector = 0; vector < wx->num_q_vectors; vector++) { 44 struct wx_q_vector *q_vector = wx->q_vector[vector]; 45 struct msix_entry *entry = &wx->msix_q_entries[vector]; 46 47 if (q_vector->tx.ring && q_vector->rx.ring) 48 snprintf(q_vector->name, sizeof(q_vector->name) - 1, 49 "%s-TxRx-%d", netdev->name, entry->entry); 50 else 51 /* skip this unused q_vector */ 52 continue; 53 54 err = request_irq(entry->vector, wx_msix_clean_rings, 0, 55 q_vector->name, q_vector); 56 if (err) { 57 wx_err(wx, "request_irq failed for MSIX interrupt %s Error: %d\n", 58 q_vector->name, err); 59 goto free_queue_irqs; 60 } 61 } 62 63 return 0; 64 65 free_queue_irqs: 66 while (vector) { 67 vector--; 68 free_irq(wx->msix_q_entries[vector].vector, 69 wx->q_vector[vector]); 70 } 71 wx_reset_interrupt_capability(wx); 72 return err; 73 } 74 75 static int txgbe_request_gpio_irq(struct txgbe *txgbe) 76 { 77 txgbe->gpio_irq = irq_find_mapping(txgbe->misc.domain, TXGBE_IRQ_GPIO); 78 return request_threaded_irq(txgbe->gpio_irq, NULL, 79 txgbe_gpio_irq_handler, 80 IRQF_ONESHOT, "txgbe-gpio-irq", txgbe); 81 } 82 83 static int txgbe_request_link_irq(struct txgbe *txgbe) 84 { 85 txgbe->link_irq = irq_find_mapping(txgbe->misc.domain, TXGBE_IRQ_LINK); 86 return request_threaded_irq(txgbe->link_irq, NULL, 87 txgbe_link_irq_handler, 88 IRQF_ONESHOT, "txgbe-link-irq", txgbe); 89 } 90 91 static const struct irq_chip txgbe_irq_chip = { 92 .name = "txgbe-misc-irq", 93 }; 94 95 static int txgbe_misc_irq_domain_map(struct irq_domain *d, 96 unsigned int irq, 97 irq_hw_number_t hwirq) 98 { 99 struct txgbe *txgbe = d->host_data; 100 101 irq_set_chip_data(irq, txgbe); 102 irq_set_chip(irq, &txgbe->misc.chip); 103 irq_set_nested_thread(irq, true); 104 irq_set_noprobe(irq); 105 106 return 0; 107 } 108 109 static const struct irq_domain_ops txgbe_misc_irq_domain_ops = { 110 .map = txgbe_misc_irq_domain_map, 111 }; 112 113 static irqreturn_t txgbe_misc_irq_handle(int irq, void *data) 114 { 115 struct wx_q_vector *q_vector; 116 struct txgbe *txgbe = data; 117 struct wx *wx = txgbe->wx; 118 u32 eicr; 119 120 if (wx->pdev->msix_enabled) 121 return IRQ_WAKE_THREAD; 122 123 eicr = wx_misc_isb(wx, WX_ISB_VEC0); 124 if (!eicr) { 125 /* shared interrupt alert! 126 * the interrupt that we masked before the ICR read. 127 */ 128 if (netif_running(wx->netdev)) 129 txgbe_irq_enable(wx, true); 130 return IRQ_NONE; /* Not our interrupt */ 131 } 132 wx->isb_mem[WX_ISB_VEC0] = 0; 133 if (!(wx->pdev->msi_enabled)) 134 wr32(wx, WX_PX_INTA, 1); 135 136 /* would disable interrupts here but it is auto disabled */ 137 q_vector = wx->q_vector[0]; 138 napi_schedule_irqoff(&q_vector->napi); 139 140 return IRQ_WAKE_THREAD; 141 } 142 143 static irqreturn_t txgbe_misc_irq_thread_fn(int irq, void *data) 144 { 145 struct txgbe *txgbe = data; 146 struct wx *wx = txgbe->wx; 147 unsigned int nhandled = 0; 148 unsigned int sub_irq; 149 u32 eicr; 150 151 eicr = wx_misc_isb(wx, WX_ISB_MISC); 152 if (eicr & TXGBE_PX_MISC_GPIO) { 153 sub_irq = irq_find_mapping(txgbe->misc.domain, TXGBE_IRQ_GPIO); 154 handle_nested_irq(sub_irq); 155 nhandled++; 156 } 157 if (eicr & (TXGBE_PX_MISC_ETH_LK | TXGBE_PX_MISC_ETH_LKDN | 158 TXGBE_PX_MISC_ETH_AN)) { 159 sub_irq = irq_find_mapping(txgbe->misc.domain, TXGBE_IRQ_LINK); 160 handle_nested_irq(sub_irq); 161 nhandled++; 162 } 163 164 wx_intr_enable(wx, TXGBE_INTR_MISC); 165 return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE); 166 } 167 168 static void txgbe_del_irq_domain(struct txgbe *txgbe) 169 { 170 int hwirq, virq; 171 172 for (hwirq = 0; hwirq < txgbe->misc.nirqs; hwirq++) { 173 virq = irq_find_mapping(txgbe->misc.domain, hwirq); 174 irq_dispose_mapping(virq); 175 } 176 177 irq_domain_remove(txgbe->misc.domain); 178 } 179 180 void txgbe_free_misc_irq(struct txgbe *txgbe) 181 { 182 free_irq(txgbe->gpio_irq, txgbe); 183 free_irq(txgbe->link_irq, txgbe); 184 free_irq(txgbe->misc.irq, txgbe); 185 txgbe_del_irq_domain(txgbe); 186 } 187 188 int txgbe_setup_misc_irq(struct txgbe *txgbe) 189 { 190 unsigned long flags = IRQF_ONESHOT; 191 struct wx *wx = txgbe->wx; 192 int hwirq, err; 193 194 txgbe->misc.nirqs = 2; 195 txgbe->misc.domain = irq_domain_add_simple(NULL, txgbe->misc.nirqs, 0, 196 &txgbe_misc_irq_domain_ops, txgbe); 197 if (!txgbe->misc.domain) 198 return -ENOMEM; 199 200 for (hwirq = 0; hwirq < txgbe->misc.nirqs; hwirq++) 201 irq_create_mapping(txgbe->misc.domain, hwirq); 202 203 txgbe->misc.chip = txgbe_irq_chip; 204 if (wx->pdev->msix_enabled) { 205 txgbe->misc.irq = wx->msix_entry->vector; 206 } else { 207 txgbe->misc.irq = wx->pdev->irq; 208 if (!wx->pdev->msi_enabled) 209 flags |= IRQF_SHARED; 210 } 211 212 err = request_threaded_irq(txgbe->misc.irq, txgbe_misc_irq_handle, 213 txgbe_misc_irq_thread_fn, 214 flags, 215 wx->netdev->name, txgbe); 216 if (err) 217 goto del_misc_irq; 218 219 err = txgbe_request_gpio_irq(txgbe); 220 if (err) 221 goto free_msic_irq; 222 223 err = txgbe_request_link_irq(txgbe); 224 if (err) 225 goto free_gpio_irq; 226 227 wx->misc_irq_domain = true; 228 229 return 0; 230 231 free_gpio_irq: 232 free_irq(txgbe->gpio_irq, txgbe); 233 free_msic_irq: 234 free_irq(txgbe->misc.irq, txgbe); 235 del_misc_irq: 236 txgbe_del_irq_domain(txgbe); 237 238 return err; 239 } 240