Skip to content

Commit aefd013

Browse files
Jiawen Wudavem330
authored andcommitted
net: txgbe: use irq_domain for interrupt controller
In the current interrupt controller, the MAC interrupt acts as the parent interrupt in the GPIO IRQ chip. But when the number of Rx/Tx ring changes, the PCI IRQ vector needs to be reallocated. Then this interrupt controller would be corrupted. So use irq_domain structure to avoid the above problem. Signed-off-by: Jiawen Wu <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 63aabc3 commit aefd013

File tree

9 files changed

+193
-54
lines changed

9 files changed

+193
-54
lines changed

drivers/net/ethernet/wangxun/libwx/wx_hw.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1958,8 +1958,6 @@ int wx_sw_init(struct wx *wx)
19581958
return -ENOMEM;
19591959
}
19601960

1961-
wx->msix_in_use = false;
1962-
19631961
return 0;
19641962
}
19651963
EXPORT_SYMBOL(wx_sw_init);

drivers/net/ethernet/wangxun/libwx/wx_lib.c

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1614,14 +1614,12 @@ static int wx_acquire_msix_vectors(struct wx *wx)
16141614
/* One for non-queue interrupts */
16151615
nvecs += 1;
16161616

1617-
if (!wx->msix_in_use) {
1618-
wx->msix_entry = kcalloc(1, sizeof(struct msix_entry),
1619-
GFP_KERNEL);
1620-
if (!wx->msix_entry) {
1621-
kfree(wx->msix_q_entries);
1622-
wx->msix_q_entries = NULL;
1623-
return -ENOMEM;
1624-
}
1617+
wx->msix_entry = kcalloc(1, sizeof(struct msix_entry),
1618+
GFP_KERNEL);
1619+
if (!wx->msix_entry) {
1620+
kfree(wx->msix_q_entries);
1621+
wx->msix_q_entries = NULL;
1622+
return -ENOMEM;
16251623
}
16261624

16271625
nvecs = pci_alloc_irq_vectors_affinity(wx->pdev, nvecs,
@@ -1931,10 +1929,8 @@ void wx_reset_interrupt_capability(struct wx *wx)
19311929
if (pdev->msix_enabled) {
19321930
kfree(wx->msix_q_entries);
19331931
wx->msix_q_entries = NULL;
1934-
if (!wx->msix_in_use) {
1935-
kfree(wx->msix_entry);
1936-
wx->msix_entry = NULL;
1937-
}
1932+
kfree(wx->msix_entry);
1933+
wx->msix_entry = NULL;
19381934
}
19391935
pci_free_irq_vectors(wx->pdev);
19401936
}

drivers/net/ethernet/wangxun/libwx/wx_type.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1047,7 +1047,6 @@ struct wx {
10471047
unsigned int queues_per_pool;
10481048
struct msix_entry *msix_q_entries;
10491049
struct msix_entry *msix_entry;
1050-
bool msix_in_use;
10511050
struct wx_ring_feature ring_feature[RING_F_ARRAY_SIZE];
10521051

10531052
/* misc interrupt status block */

drivers/net/ethernet/wangxun/txgbe/txgbe_irq.c

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
// SPDX-License-Identifier: GPL-2.0
22
/* Copyright (c) 2015 - 2024 Beijing WangXun Technology Co., Ltd. */
33

4+
#include <linux/irqdomain.h>
45
#include <linux/pci.h>
56

67
#include "../libwx/wx_type.h"
78
#include "../libwx/wx_lib.h"
89
#include "../libwx/wx_hw.h"
910
#include "txgbe_type.h"
11+
#include "txgbe_phy.h"
1012
#include "txgbe_irq.h"
1113

1214
/**
@@ -135,3 +137,133 @@ int txgbe_request_irq(struct wx *wx)
135137

136138
return err;
137139
}
140+
141+
static int txgbe_request_gpio_irq(struct txgbe *txgbe)
142+
{
143+
txgbe->gpio_irq = irq_find_mapping(txgbe->misc.domain, TXGBE_IRQ_GPIO);
144+
return request_threaded_irq(txgbe->gpio_irq, NULL,
145+
txgbe_gpio_irq_handler,
146+
IRQF_ONESHOT, "txgbe-gpio-irq", txgbe);
147+
}
148+
149+
static int txgbe_request_link_irq(struct txgbe *txgbe)
150+
{
151+
txgbe->link_irq = irq_find_mapping(txgbe->misc.domain, TXGBE_IRQ_LINK);
152+
return request_threaded_irq(txgbe->link_irq, NULL,
153+
txgbe_link_irq_handler,
154+
IRQF_ONESHOT, "txgbe-link-irq", txgbe);
155+
}
156+
157+
static const struct irq_chip txgbe_irq_chip = {
158+
.name = "txgbe-misc-irq",
159+
};
160+
161+
static int txgbe_misc_irq_domain_map(struct irq_domain *d,
162+
unsigned int irq,
163+
irq_hw_number_t hwirq)
164+
{
165+
struct txgbe *txgbe = d->host_data;
166+
167+
irq_set_chip_data(irq, txgbe);
168+
irq_set_chip(irq, &txgbe->misc.chip);
169+
irq_set_nested_thread(irq, true);
170+
irq_set_noprobe(irq);
171+
172+
return 0;
173+
}
174+
175+
static const struct irq_domain_ops txgbe_misc_irq_domain_ops = {
176+
.map = txgbe_misc_irq_domain_map,
177+
};
178+
179+
static irqreturn_t txgbe_misc_irq_handle(int irq, void *data)
180+
{
181+
struct txgbe *txgbe = data;
182+
struct wx *wx = txgbe->wx;
183+
unsigned int nhandled = 0;
184+
unsigned int sub_irq;
185+
u32 eicr;
186+
187+
eicr = wx_misc_isb(wx, WX_ISB_MISC);
188+
if (eicr & TXGBE_PX_MISC_GPIO) {
189+
sub_irq = irq_find_mapping(txgbe->misc.domain, TXGBE_IRQ_GPIO);
190+
handle_nested_irq(sub_irq);
191+
nhandled++;
192+
}
193+
if (eicr & (TXGBE_PX_MISC_ETH_LK | TXGBE_PX_MISC_ETH_LKDN |
194+
TXGBE_PX_MISC_ETH_AN)) {
195+
sub_irq = irq_find_mapping(txgbe->misc.domain, TXGBE_IRQ_LINK);
196+
handle_nested_irq(sub_irq);
197+
nhandled++;
198+
}
199+
200+
wx_intr_enable(wx, TXGBE_INTR_MISC);
201+
return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE);
202+
}
203+
204+
static void txgbe_del_irq_domain(struct txgbe *txgbe)
205+
{
206+
int hwirq, virq;
207+
208+
for (hwirq = 0; hwirq < txgbe->misc.nirqs; hwirq++) {
209+
virq = irq_find_mapping(txgbe->misc.domain, hwirq);
210+
irq_dispose_mapping(virq);
211+
}
212+
213+
irq_domain_remove(txgbe->misc.domain);
214+
}
215+
216+
void txgbe_free_misc_irq(struct txgbe *txgbe)
217+
{
218+
free_irq(txgbe->gpio_irq, txgbe);
219+
free_irq(txgbe->link_irq, txgbe);
220+
free_irq(txgbe->misc.irq, txgbe);
221+
txgbe_del_irq_domain(txgbe);
222+
}
223+
224+
int txgbe_setup_misc_irq(struct txgbe *txgbe)
225+
{
226+
struct wx *wx = txgbe->wx;
227+
int hwirq, err;
228+
229+
txgbe->misc.nirqs = 2;
230+
txgbe->misc.domain = irq_domain_add_simple(NULL, txgbe->misc.nirqs, 0,
231+
&txgbe_misc_irq_domain_ops, txgbe);
232+
if (!txgbe->misc.domain)
233+
return -ENOMEM;
234+
235+
for (hwirq = 0; hwirq < txgbe->misc.nirqs; hwirq++)
236+
irq_create_mapping(txgbe->misc.domain, hwirq);
237+
238+
txgbe->misc.chip = txgbe_irq_chip;
239+
if (wx->pdev->msix_enabled)
240+
txgbe->misc.irq = wx->msix_entry->vector;
241+
else
242+
txgbe->misc.irq = wx->pdev->irq;
243+
244+
err = request_threaded_irq(txgbe->misc.irq, NULL,
245+
txgbe_misc_irq_handle,
246+
IRQF_ONESHOT,
247+
wx->netdev->name, txgbe);
248+
if (err)
249+
goto del_misc_irq;
250+
251+
err = txgbe_request_gpio_irq(txgbe);
252+
if (err)
253+
goto free_msic_irq;
254+
255+
err = txgbe_request_link_irq(txgbe);
256+
if (err)
257+
goto free_gpio_irq;
258+
259+
return 0;
260+
261+
free_gpio_irq:
262+
free_irq(txgbe->gpio_irq, txgbe);
263+
free_msic_irq:
264+
free_irq(txgbe->misc.irq, txgbe);
265+
del_misc_irq:
266+
txgbe_del_irq_domain(txgbe);
267+
268+
return err;
269+
}

drivers/net/ethernet/wangxun/txgbe/txgbe_irq.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,5 @@
33

44
void txgbe_irq_enable(struct wx *wx, bool queues);
55
int txgbe_request_irq(struct wx *wx);
6+
void txgbe_free_misc_irq(struct txgbe *txgbe);
7+
int txgbe_setup_misc_irq(struct txgbe *txgbe);

drivers/net/ethernet/wangxun/txgbe/txgbe_main.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,7 @@ static void txgbe_shutdown(struct pci_dev *pdev)
392392
int txgbe_setup_tc(struct net_device *dev, u8 tc)
393393
{
394394
struct wx *wx = netdev_priv(dev);
395+
struct txgbe *txgbe = wx->priv;
395396

396397
/* Hardware has to reinitialize queues and interrupts to
397398
* match packet buffer alignment. Unfortunately, the
@@ -402,6 +403,7 @@ int txgbe_setup_tc(struct net_device *dev, u8 tc)
402403
else
403404
txgbe_reset(wx);
404405

406+
txgbe_free_misc_irq(txgbe);
405407
wx_clear_interrupt_scheme(wx);
406408

407409
if (tc)
@@ -410,6 +412,7 @@ int txgbe_setup_tc(struct net_device *dev, u8 tc)
410412
netdev_reset_tc(dev);
411413

412414
wx_init_interrupt_scheme(wx);
415+
txgbe_setup_misc_irq(txgbe);
413416

414417
if (netif_running(dev))
415418
txgbe_open(dev);
@@ -625,10 +628,14 @@ static int txgbe_probe(struct pci_dev *pdev,
625628
txgbe->wx = wx;
626629
wx->priv = txgbe;
627630

628-
err = txgbe_init_phy(txgbe);
631+
err = txgbe_setup_misc_irq(txgbe);
629632
if (err)
630633
goto err_release_hw;
631634

635+
err = txgbe_init_phy(txgbe);
636+
if (err)
637+
goto err_free_misc_irq;
638+
632639
err = register_netdev(netdev);
633640
if (err)
634641
goto err_remove_phy;
@@ -655,6 +662,8 @@ static int txgbe_probe(struct pci_dev *pdev,
655662

656663
err_remove_phy:
657664
txgbe_remove_phy(txgbe);
665+
err_free_misc_irq:
666+
txgbe_free_misc_irq(txgbe);
658667
err_release_hw:
659668
wx_clear_interrupt_scheme(wx);
660669
wx_control_hw(wx, false);
@@ -687,6 +696,7 @@ static void txgbe_remove(struct pci_dev *pdev)
687696
unregister_netdev(netdev);
688697

689698
txgbe_remove_phy(txgbe);
699+
txgbe_free_misc_irq(txgbe);
690700

691701
pci_release_selected_regions(pdev,
692702
pci_select_bars(pdev, IORESOURCE_MEM));

drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c

Lines changed: 21 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,21 @@ static int txgbe_phylink_init(struct txgbe *txgbe)
292292
return 0;
293293
}
294294

295+
irqreturn_t txgbe_link_irq_handler(int irq, void *data)
296+
{
297+
struct txgbe *txgbe = data;
298+
struct wx *wx = txgbe->wx;
299+
u32 status;
300+
bool up;
301+
302+
status = rd32(wx, TXGBE_CFG_PORT_ST);
303+
up = !!(status & TXGBE_CFG_PORT_ST_LINK_UP);
304+
305+
phylink_mac_change(wx->phylink, up);
306+
307+
return IRQ_HANDLED;
308+
}
309+
295310
static int txgbe_gpio_get(struct gpio_chip *chip, unsigned int offset)
296311
{
297312
struct wx *wx = gpiochip_get_data(chip);
@@ -437,7 +452,7 @@ static int txgbe_gpio_set_type(struct irq_data *d, unsigned int type)
437452
}
438453

439454
static const struct irq_chip txgbe_gpio_irq_chip = {
440-
.name = "txgbe_gpio_irq",
455+
.name = "txgbe-gpio-irq",
441456
.irq_ack = txgbe_gpio_irq_ack,
442457
.irq_mask = txgbe_gpio_irq_mask,
443458
.irq_unmask = txgbe_gpio_irq_unmask,
@@ -446,20 +461,14 @@ static const struct irq_chip txgbe_gpio_irq_chip = {
446461
GPIOCHIP_IRQ_RESOURCE_HELPERS,
447462
};
448463

449-
static void txgbe_irq_handler(struct irq_desc *desc)
464+
irqreturn_t txgbe_gpio_irq_handler(int irq, void *data)
450465
{
451-
struct irq_chip *chip = irq_desc_get_chip(desc);
452-
struct wx *wx = irq_desc_get_handler_data(desc);
453-
struct txgbe *txgbe = wx->priv;
466+
struct txgbe *txgbe = data;
467+
struct wx *wx = txgbe->wx;
454468
irq_hw_number_t hwirq;
455469
unsigned long gpioirq;
456470
struct gpio_chip *gc;
457471
unsigned long flags;
458-
u32 eicr;
459-
460-
eicr = wx_misc_isb(wx, WX_ISB_MISC);
461-
462-
chained_irq_enter(chip, desc);
463472

464473
gpioirq = rd32(wx, WX_GPIO_INTSTATUS);
465474

@@ -468,7 +477,7 @@ static void txgbe_irq_handler(struct irq_desc *desc)
468477
int gpio = irq_find_mapping(gc->irq.domain, hwirq);
469478
u32 irq_type = irq_get_trigger_type(gpio);
470479

471-
generic_handle_domain_irq(gc->irq.domain, hwirq);
480+
handle_nested_irq(gpio);
472481

473482
if ((irq_type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) {
474483
raw_spin_lock_irqsave(&wx->gpio_lock, flags);
@@ -477,17 +486,7 @@ static void txgbe_irq_handler(struct irq_desc *desc)
477486
}
478487
}
479488

480-
chained_irq_exit(chip, desc);
481-
482-
if (eicr & (TXGBE_PX_MISC_ETH_LK | TXGBE_PX_MISC_ETH_LKDN |
483-
TXGBE_PX_MISC_ETH_AN)) {
484-
u32 reg = rd32(wx, TXGBE_CFG_PORT_ST);
485-
486-
phylink_mac_change(wx->phylink, !!(reg & TXGBE_CFG_PORT_ST_LINK_UP));
487-
}
488-
489-
/* unmask interrupt */
490-
wx_intr_enable(wx, TXGBE_INTR_MISC);
489+
return IRQ_HANDLED;
491490
}
492491

493492
static int txgbe_gpio_init(struct txgbe *txgbe)
@@ -524,19 +523,6 @@ static int txgbe_gpio_init(struct txgbe *txgbe)
524523

525524
girq = &gc->irq;
526525
gpio_irq_chip_set_chip(girq, &txgbe_gpio_irq_chip);
527-
girq->parent_handler = txgbe_irq_handler;
528-
girq->parent_handler_data = wx;
529-
girq->num_parents = 1;
530-
girq->parents = devm_kcalloc(dev, girq->num_parents,
531-
sizeof(*girq->parents), GFP_KERNEL);
532-
if (!girq->parents)
533-
return -ENOMEM;
534-
535-
/* now only suuported on MSI-X interrupt */
536-
if (!wx->msix_entry)
537-
return -EPERM;
538-
539-
girq->parents[0] = wx->msix_entry->vector;
540526
girq->default_type = IRQ_TYPE_NONE;
541527
girq->handler = handle_bad_irq;
542528

@@ -754,8 +740,6 @@ int txgbe_init_phy(struct txgbe *txgbe)
754740
goto err_unregister_i2c;
755741
}
756742

757-
wx->msix_in_use = true;
758-
759743
return 0;
760744

761745
err_unregister_i2c:
@@ -788,5 +772,4 @@ void txgbe_remove_phy(struct txgbe *txgbe)
788772
phylink_destroy(txgbe->wx->phylink);
789773
xpcs_destroy(txgbe->xpcs);
790774
software_node_unregister_node_group(txgbe->nodes.group);
791-
txgbe->wx->msix_in_use = false;
792775
}

drivers/net/ethernet/wangxun/txgbe/txgbe_phy.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
#ifndef _TXGBE_PHY_H_
55
#define _TXGBE_PHY_H_
66

7+
irqreturn_t txgbe_gpio_irq_handler(int irq, void *data);
8+
irqreturn_t txgbe_link_irq_handler(int irq, void *data);
79
int txgbe_init_phy(struct txgbe *txgbe);
810
void txgbe_remove_phy(struct txgbe *txgbe);
911

0 commit comments

Comments
 (0)