net: txgbe: remove GPIO interrupt controller

Since the GPIO interrupt controller is always not working properly, we need
to constantly add workaround to cope with hardware deficiencies. So just
remove GPIO interrupt controller, and let the SFP driver poll the GPIO
status.

Fixes: b4a2496c17 ("net: txgbe: fix GPIO interrupt blocking")
Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
Link: https://patch.msgid.link/20241115071527.1129458-1-jiawenwu@trustnetic.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jiawen Wu 2024-11-15 15:15:27 +08:00 committed by Jakub Kicinski
parent 4be4a91d53
commit e867ed3ac8
5 changed files with 4 additions and 196 deletions

View file

@ -72,14 +72,6 @@ free_queue_irqs:
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);
@ -149,11 +141,6 @@ static irqreturn_t txgbe_misc_irq_thread_fn(int irq, void *data)
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);
@ -179,7 +166,6 @@ static void txgbe_del_irq_domain(struct txgbe *txgbe)
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);
@ -191,7 +177,7 @@ int txgbe_setup_misc_irq(struct txgbe *txgbe)
struct wx *wx = txgbe->wx;
int hwirq, err;
txgbe->misc.nirqs = 2;
txgbe->misc.nirqs = 1;
txgbe->misc.domain = irq_domain_add_simple(NULL, txgbe->misc.nirqs, 0,
&txgbe_misc_irq_domain_ops, txgbe);
if (!txgbe->misc.domain)
@ -216,20 +202,14 @@ int txgbe_setup_misc_irq(struct txgbe *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;
goto free_msic_irq;
wx->misc_irq_domain = true;
return 0;
free_gpio_irq:
free_irq(txgbe->gpio_irq, txgbe);
free_msic_irq:
free_irq(txgbe->misc.irq, txgbe);
del_misc_irq:

View file

@ -82,7 +82,6 @@ static void txgbe_up_complete(struct wx *wx)
{
struct net_device *netdev = wx->netdev;
txgbe_reinit_gpio_intr(wx);
wx_control_hw(wx, true);
wx_configure_vectors(wx);

View file

@ -358,169 +358,8 @@ static int txgbe_gpio_direction_out(struct gpio_chip *chip, unsigned int offset,
return 0;
}
static void txgbe_gpio_irq_ack(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
irq_hw_number_t hwirq = irqd_to_hwirq(d);
struct wx *wx = gpiochip_get_data(gc);
unsigned long flags;
raw_spin_lock_irqsave(&wx->gpio_lock, flags);
wr32(wx, WX_GPIO_EOI, BIT(hwirq));
raw_spin_unlock_irqrestore(&wx->gpio_lock, flags);
}
static void txgbe_gpio_irq_mask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
irq_hw_number_t hwirq = irqd_to_hwirq(d);
struct wx *wx = gpiochip_get_data(gc);
unsigned long flags;
gpiochip_disable_irq(gc, hwirq);
raw_spin_lock_irqsave(&wx->gpio_lock, flags);
wr32m(wx, WX_GPIO_INTMASK, BIT(hwirq), BIT(hwirq));
raw_spin_unlock_irqrestore(&wx->gpio_lock, flags);
}
static void txgbe_gpio_irq_unmask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
irq_hw_number_t hwirq = irqd_to_hwirq(d);
struct wx *wx = gpiochip_get_data(gc);
unsigned long flags;
gpiochip_enable_irq(gc, hwirq);
raw_spin_lock_irqsave(&wx->gpio_lock, flags);
wr32m(wx, WX_GPIO_INTMASK, BIT(hwirq), 0);
raw_spin_unlock_irqrestore(&wx->gpio_lock, flags);
}
static void txgbe_toggle_trigger(struct gpio_chip *gc, unsigned int offset)
{
struct wx *wx = gpiochip_get_data(gc);
u32 pol, val;
pol = rd32(wx, WX_GPIO_POLARITY);
val = rd32(wx, WX_GPIO_EXT);
if (val & BIT(offset))
pol &= ~BIT(offset);
else
pol |= BIT(offset);
wr32(wx, WX_GPIO_POLARITY, pol);
}
static int txgbe_gpio_set_type(struct irq_data *d, unsigned int type)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
irq_hw_number_t hwirq = irqd_to_hwirq(d);
struct wx *wx = gpiochip_get_data(gc);
u32 level, polarity, mask;
unsigned long flags;
mask = BIT(hwirq);
if (type & IRQ_TYPE_LEVEL_MASK) {
level = 0;
irq_set_handler_locked(d, handle_level_irq);
} else {
level = mask;
irq_set_handler_locked(d, handle_edge_irq);
}
if (type == IRQ_TYPE_EDGE_RISING || type == IRQ_TYPE_LEVEL_HIGH)
polarity = mask;
else
polarity = 0;
raw_spin_lock_irqsave(&wx->gpio_lock, flags);
wr32m(wx, WX_GPIO_INTEN, mask, mask);
wr32m(wx, WX_GPIO_INTTYPE_LEVEL, mask, level);
if (type == IRQ_TYPE_EDGE_BOTH)
txgbe_toggle_trigger(gc, hwirq);
else
wr32m(wx, WX_GPIO_POLARITY, mask, polarity);
raw_spin_unlock_irqrestore(&wx->gpio_lock, flags);
return 0;
}
static const struct irq_chip txgbe_gpio_irq_chip = {
.name = "txgbe-gpio-irq",
.irq_ack = txgbe_gpio_irq_ack,
.irq_mask = txgbe_gpio_irq_mask,
.irq_unmask = txgbe_gpio_irq_unmask,
.irq_set_type = txgbe_gpio_set_type,
.flags = IRQCHIP_IMMUTABLE,
GPIOCHIP_IRQ_RESOURCE_HELPERS,
};
irqreturn_t txgbe_gpio_irq_handler(int irq, void *data)
{
struct txgbe *txgbe = data;
struct wx *wx = txgbe->wx;
irq_hw_number_t hwirq;
unsigned long gpioirq;
struct gpio_chip *gc;
unsigned long flags;
gpioirq = rd32(wx, WX_GPIO_INTSTATUS);
gc = txgbe->gpio;
for_each_set_bit(hwirq, &gpioirq, gc->ngpio) {
int gpio = irq_find_mapping(gc->irq.domain, hwirq);
struct irq_data *d = irq_get_irq_data(gpio);
u32 irq_type = irq_get_trigger_type(gpio);
txgbe_gpio_irq_ack(d);
handle_nested_irq(gpio);
if ((irq_type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) {
raw_spin_lock_irqsave(&wx->gpio_lock, flags);
txgbe_toggle_trigger(gc, hwirq);
raw_spin_unlock_irqrestore(&wx->gpio_lock, flags);
}
}
return IRQ_HANDLED;
}
void txgbe_reinit_gpio_intr(struct wx *wx)
{
struct txgbe *txgbe = wx->priv;
irq_hw_number_t hwirq;
unsigned long gpioirq;
struct gpio_chip *gc;
unsigned long flags;
/* for gpio interrupt pending before irq enable */
gpioirq = rd32(wx, WX_GPIO_INTSTATUS);
gc = txgbe->gpio;
for_each_set_bit(hwirq, &gpioirq, gc->ngpio) {
int gpio = irq_find_mapping(gc->irq.domain, hwirq);
struct irq_data *d = irq_get_irq_data(gpio);
u32 irq_type = irq_get_trigger_type(gpio);
txgbe_gpio_irq_ack(d);
if ((irq_type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) {
raw_spin_lock_irqsave(&wx->gpio_lock, flags);
txgbe_toggle_trigger(gc, hwirq);
raw_spin_unlock_irqrestore(&wx->gpio_lock, flags);
}
}
}
static int txgbe_gpio_init(struct txgbe *txgbe)
{
struct gpio_irq_chip *girq;
struct gpio_chip *gc;
struct device *dev;
struct wx *wx;
@ -550,11 +389,6 @@ static int txgbe_gpio_init(struct txgbe *txgbe)
gc->direction_input = txgbe_gpio_direction_in;
gc->direction_output = txgbe_gpio_direction_out;
girq = &gc->irq;
gpio_irq_chip_set_chip(girq, &txgbe_gpio_irq_chip);
girq->default_type = IRQ_TYPE_NONE;
girq->handler = handle_bad_irq;
ret = devm_gpiochip_add_data(dev, gc, wx);
if (ret)
return ret;

View file

@ -4,8 +4,6 @@
#ifndef _TXGBE_PHY_H_
#define _TXGBE_PHY_H_
irqreturn_t txgbe_gpio_irq_handler(int irq, void *data);
void txgbe_reinit_gpio_intr(struct wx *wx);
irqreturn_t txgbe_link_irq_handler(int irq, void *data);
int txgbe_init_phy(struct txgbe *txgbe);
void txgbe_remove_phy(struct txgbe *txgbe);

View file

@ -75,8 +75,7 @@
#define TXGBE_PX_MISC_IEN_MASK \
(TXGBE_PX_MISC_ETH_LKDN | TXGBE_PX_MISC_DEV_RST | \
TXGBE_PX_MISC_ETH_EVENT | TXGBE_PX_MISC_ETH_LK | \
TXGBE_PX_MISC_ETH_AN | TXGBE_PX_MISC_INT_ERR | \
TXGBE_PX_MISC_GPIO)
TXGBE_PX_MISC_ETH_AN | TXGBE_PX_MISC_INT_ERR)
/* Port cfg registers */
#define TXGBE_CFG_PORT_ST 0x14404
@ -313,8 +312,7 @@ struct txgbe_nodes {
};
enum txgbe_misc_irqs {
TXGBE_IRQ_GPIO = 0,
TXGBE_IRQ_LINK,
TXGBE_IRQ_LINK = 0,
TXGBE_IRQ_MAX
};
@ -335,7 +333,6 @@ struct txgbe {
struct clk_lookup *clock;
struct clk *clk;
struct gpio_chip *gpio;
unsigned int gpio_irq;
unsigned int link_irq;
/* flow director */