File Index
Files and directories
Sign in
FILE

txgbe_irq.c

File preview with syntax highlighting.

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