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(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(int_status, 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(&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(priv->error_irq, mlxbf_gige_error_intr, 0, 97 "mlxbf_gige_error", priv); 98 if (err) { 99 dev_err(priv->dev, "Request error_irq failure\n"); 100 return err; 101 } 102 103 err = request_irq(priv->rx_irq, mlxbf_gige_rx_intr, 0, 104 "mlxbf_gige_rx", 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(priv->llu_plu_irq, mlxbf_gige_llu_plu_intr, 0, 111 "mlxbf_gige_llu_plu", 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