1// SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause
2
3/* Interrupt related logic for Mellanox Gigabit Ethernet driver
4 *
5 * Copyright (C) 2020-2021 NVIDIA CORPORATION & AFFILIATES
6 */
7
8#include <linux/interrupt.h>
9
10#include "mlxbf_gige.h"
11#include "mlxbf_gige_regs.h"
12
13static irqreturn_t mlxbf_gige_error_intr(int irq, void *dev_id)
14{
15 struct mlxbf_gige *priv;
16 u64 int_status;
17
18 priv = dev_id;
19
20 int_status = readq(addr: priv->base + MLXBF_GIGE_INT_STATUS);
21
22 if (int_status & MLXBF_GIGE_INT_STATUS_HW_ACCESS_ERROR)
23 priv->stats.hw_access_errors++;
24
25 if (int_status & MLXBF_GIGE_INT_STATUS_TX_CHECKSUM_INPUTS) {
26 priv->stats.tx_invalid_checksums++;
27 /* This error condition is latched into MLXBF_GIGE_INT_STATUS
28 * when the GigE silicon operates on the offending
29 * TX WQE. The write to MLXBF_GIGE_INT_STATUS at the bottom
30 * of this routine clears this error condition.
31 */
32 }
33
34 if (int_status & MLXBF_GIGE_INT_STATUS_TX_SMALL_FRAME_SIZE) {
35 priv->stats.tx_small_frames++;
36 /* This condition happens when the networking stack invokes
37 * this driver's "start_xmit()" method with a packet whose
38 * size < 60 bytes. The GigE silicon will automatically pad
39 * this small frame up to a minimum-sized frame before it is
40 * sent. The "tx_small_frame" condition is latched into the
41 * MLXBF_GIGE_INT_STATUS register when the GigE silicon
42 * operates on the offending TX WQE. The write to
43 * MLXBF_GIGE_INT_STATUS at the bottom of this routine
44 * clears this condition.
45 */
46 }
47
48 if (int_status & MLXBF_GIGE_INT_STATUS_TX_PI_CI_EXCEED_WQ_SIZE)
49 priv->stats.tx_index_errors++;
50
51 if (int_status & MLXBF_GIGE_INT_STATUS_SW_CONFIG_ERROR)
52 priv->stats.sw_config_errors++;
53
54 if (int_status & MLXBF_GIGE_INT_STATUS_SW_ACCESS_ERROR)
55 priv->stats.sw_access_errors++;
56
57 /* Clear all error interrupts by writing '1' back to
58 * all the asserted bits in INT_STATUS. Do not write
59 * '1' back to 'receive packet' bit, since that is
60 * managed separately.
61 */
62
63 int_status &= ~MLXBF_GIGE_INT_STATUS_RX_RECEIVE_PACKET;
64
65 writeq(val: int_status, addr: priv->base + MLXBF_GIGE_INT_STATUS);
66
67 return IRQ_HANDLED;
68}
69
70static irqreturn_t mlxbf_gige_rx_intr(int irq, void *dev_id)
71{
72 struct mlxbf_gige *priv;
73
74 priv = dev_id;
75
76 /* NOTE: GigE silicon automatically disables "packet rx" interrupt by
77 * setting MLXBF_GIGE_INT_MASK bit0 upon triggering the interrupt
78 * to the ARM cores. Software needs to re-enable "packet rx"
79 * interrupts by clearing MLXBF_GIGE_INT_MASK bit0.
80 */
81
82 napi_schedule(n: &priv->napi);
83
84 return IRQ_HANDLED;
85}
86
87static irqreturn_t mlxbf_gige_llu_plu_intr(int irq, void *dev_id)
88{
89 return IRQ_HANDLED;
90}
91
92int mlxbf_gige_request_irqs(struct mlxbf_gige *priv)
93{
94 int err;
95
96 err = request_irq(irq: priv->error_irq, handler: mlxbf_gige_error_intr, flags: 0,
97 name: "mlxbf_gige_error", dev: priv);
98 if (err) {
99 dev_err(priv->dev, "Request error_irq failure\n");
100 return err;
101 }
102
103 err = request_irq(irq: priv->rx_irq, handler: mlxbf_gige_rx_intr, flags: 0,
104 name: "mlxbf_gige_rx", dev: priv);
105 if (err) {
106 dev_err(priv->dev, "Request rx_irq failure\n");
107 goto free_error_irq;
108 }
109
110 err = request_irq(irq: priv->llu_plu_irq, handler: mlxbf_gige_llu_plu_intr, flags: 0,
111 name: "mlxbf_gige_llu_plu", dev: priv);
112 if (err) {
113 dev_err(priv->dev, "Request llu_plu_irq failure\n");
114 goto free_rx_irq;
115 }
116
117 return 0;
118
119free_rx_irq:
120 free_irq(priv->rx_irq, priv);
121
122free_error_irq:
123 free_irq(priv->error_irq, priv);
124
125 return err;
126}
127
128void mlxbf_gige_free_irqs(struct mlxbf_gige *priv)
129{
130 free_irq(priv->error_irq, priv);
131 free_irq(priv->rx_irq, priv);
132 free_irq(priv->llu_plu_irq, priv);
133}
134

source code of linux/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_intr.c