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