Commit aefd0136 authored by Jiawen Wu's avatar Jiawen Wu Committed by David S. Miller
Browse files

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: default avatarJiawen Wu <jiawenwu@trustnetic.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 63aabc3e
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -1958,8 +1958,6 @@ int wx_sw_init(struct wx *wx)
		return -ENOMEM;
	}

	wx->msix_in_use = false;

	return 0;
}
EXPORT_SYMBOL(wx_sw_init);
+8 −12
Original line number Diff line number Diff line
@@ -1614,7 +1614,6 @@ static int wx_acquire_msix_vectors(struct wx *wx)
	/* One for non-queue interrupts */
	nvecs += 1;

	if (!wx->msix_in_use) {
	wx->msix_entry = kcalloc(1, sizeof(struct msix_entry),
				 GFP_KERNEL);
	if (!wx->msix_entry) {
@@ -1622,7 +1621,6 @@ static int wx_acquire_msix_vectors(struct wx *wx)
		wx->msix_q_entries = NULL;
		return -ENOMEM;
	}
	}

	nvecs = pci_alloc_irq_vectors_affinity(wx->pdev, nvecs,
					       nvecs,
@@ -1931,11 +1929,9 @@ void wx_reset_interrupt_capability(struct wx *wx)
	if (pdev->msix_enabled) {
		kfree(wx->msix_q_entries);
		wx->msix_q_entries = NULL;
		if (!wx->msix_in_use) {
		kfree(wx->msix_entry);
		wx->msix_entry = NULL;
	}
	}
	pci_free_irq_vectors(wx->pdev);
}
EXPORT_SYMBOL(wx_reset_interrupt_capability);
+0 −1
Original line number Diff line number Diff line
@@ -1047,7 +1047,6 @@ struct wx {
	unsigned int queues_per_pool;
	struct msix_entry *msix_q_entries;
	struct msix_entry *msix_entry;
	bool msix_in_use;
	struct wx_ring_feature ring_feature[RING_F_ARRAY_SIZE];

	/* misc interrupt status block */
+132 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2015 - 2024 Beijing WangXun Technology Co., Ltd. */

#include <linux/irqdomain.h>
#include <linux/pci.h>

#include "../libwx/wx_type.h"
#include "../libwx/wx_lib.h"
#include "../libwx/wx_hw.h"
#include "txgbe_type.h"
#include "txgbe_phy.h"
#include "txgbe_irq.h"

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

	return err;
}

static int txgbe_request_gpio_irq(struct txgbe *txgbe)
{
	txgbe->gpio_irq = irq_find_mapping(txgbe->misc.domain, TXGBE_IRQ_GPIO);
	return request_threaded_irq(txgbe->gpio_irq, NULL,
				    txgbe_gpio_irq_handler,
				    IRQF_ONESHOT, "txgbe-gpio-irq", txgbe);
}

static int txgbe_request_link_irq(struct txgbe *txgbe)
{
	txgbe->link_irq = irq_find_mapping(txgbe->misc.domain, TXGBE_IRQ_LINK);
	return request_threaded_irq(txgbe->link_irq, NULL,
				    txgbe_link_irq_handler,
				    IRQF_ONESHOT, "txgbe-link-irq", txgbe);
}

static const struct irq_chip txgbe_irq_chip = {
	.name = "txgbe-misc-irq",
};

static int txgbe_misc_irq_domain_map(struct irq_domain *d,
				     unsigned int irq,
				     irq_hw_number_t hwirq)
{
	struct txgbe *txgbe = d->host_data;

	irq_set_chip_data(irq, txgbe);
	irq_set_chip(irq, &txgbe->misc.chip);
	irq_set_nested_thread(irq, true);
	irq_set_noprobe(irq);

	return 0;
}

static const struct irq_domain_ops txgbe_misc_irq_domain_ops = {
	.map = txgbe_misc_irq_domain_map,
};

static irqreturn_t txgbe_misc_irq_handle(int irq, void *data)
{
	struct txgbe *txgbe = data;
	struct wx *wx = txgbe->wx;
	unsigned int nhandled = 0;
	unsigned int sub_irq;
	u32 eicr;

	eicr = wx_misc_isb(wx, WX_ISB_MISC);
	if (eicr & TXGBE_PX_MISC_GPIO) {
		sub_irq = irq_find_mapping(txgbe->misc.domain, TXGBE_IRQ_GPIO);
		handle_nested_irq(sub_irq);
		nhandled++;
	}
	if (eicr & (TXGBE_PX_MISC_ETH_LK | TXGBE_PX_MISC_ETH_LKDN |
		    TXGBE_PX_MISC_ETH_AN)) {
		sub_irq = irq_find_mapping(txgbe->misc.domain, TXGBE_IRQ_LINK);
		handle_nested_irq(sub_irq);
		nhandled++;
	}

	wx_intr_enable(wx, TXGBE_INTR_MISC);
	return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE);
}

static void txgbe_del_irq_domain(struct txgbe *txgbe)
{
	int hwirq, virq;

	for (hwirq = 0; hwirq < txgbe->misc.nirqs; hwirq++) {
		virq = irq_find_mapping(txgbe->misc.domain, hwirq);
		irq_dispose_mapping(virq);
	}

	irq_domain_remove(txgbe->misc.domain);
}

void txgbe_free_misc_irq(struct txgbe *txgbe)
{
	free_irq(txgbe->gpio_irq, txgbe);
	free_irq(txgbe->link_irq, txgbe);
	free_irq(txgbe->misc.irq, txgbe);
	txgbe_del_irq_domain(txgbe);
}

int txgbe_setup_misc_irq(struct txgbe *txgbe)
{
	struct wx *wx = txgbe->wx;
	int hwirq, err;

	txgbe->misc.nirqs = 2;
	txgbe->misc.domain = irq_domain_add_simple(NULL, txgbe->misc.nirqs, 0,
						   &txgbe_misc_irq_domain_ops, txgbe);
	if (!txgbe->misc.domain)
		return -ENOMEM;

	for (hwirq = 0; hwirq < txgbe->misc.nirqs; hwirq++)
		irq_create_mapping(txgbe->misc.domain, hwirq);

	txgbe->misc.chip = txgbe_irq_chip;
	if (wx->pdev->msix_enabled)
		txgbe->misc.irq = wx->msix_entry->vector;
	else
		txgbe->misc.irq = wx->pdev->irq;

	err = request_threaded_irq(txgbe->misc.irq, NULL,
				   txgbe_misc_irq_handle,
				   IRQF_ONESHOT,
				   wx->netdev->name, txgbe);
	if (err)
		goto del_misc_irq;

	err = txgbe_request_gpio_irq(txgbe);
	if (err)
		goto free_msic_irq;

	err = txgbe_request_link_irq(txgbe);
	if (err)
		goto free_gpio_irq;

	return 0;

free_gpio_irq:
	free_irq(txgbe->gpio_irq, txgbe);
free_msic_irq:
	free_irq(txgbe->misc.irq, txgbe);
del_misc_irq:
	txgbe_del_irq_domain(txgbe);

	return err;
}
+2 −0
Original line number Diff line number Diff line
@@ -3,3 +3,5 @@

void txgbe_irq_enable(struct wx *wx, bool queues);
int txgbe_request_irq(struct wx *wx);
void txgbe_free_misc_irq(struct txgbe *txgbe);
int txgbe_setup_misc_irq(struct txgbe *txgbe);
Loading