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 | |
13 | static 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 | |
70 | static 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 | |
87 | static irqreturn_t mlxbf_gige_llu_plu_intr(int irq, void *dev_id) |
88 | { |
89 | return IRQ_HANDLED; |
90 | } |
91 | |
92 | int 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 | |
119 | free_rx_irq: |
120 | free_irq(priv->rx_irq, priv); |
121 | |
122 | free_error_irq: |
123 | free_irq(priv->error_irq, priv); |
124 | |
125 | return err; |
126 | } |
127 | |
128 | void 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 | |