1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2014-2023 Broadcom 3 * All rights reserved. 4 */ 5 6 #include <inttypes.h> 7 8 #include <rte_cycles.h> 9 #include <rte_malloc.h> 10 11 #include "bnxt.h" 12 #include "bnxt_irq.h" 13 #include "bnxt_ring.h" 14 #include "hsi_struct_def_dpdk.h" 15 16 /* 17 * Interrupts 18 */ 19 20 static inline void bnxt_int_handler_rearm(struct bnxt *bp, 21 struct bnxt_cp_ring_info *cpr, 22 uint32_t raw_cons) 23 { 24 cpr->cp_raw_cons = raw_cons; 25 if (BNXT_HAS_NQ(bp)) 26 bnxt_db_nq_arm(cpr); 27 else 28 B_CP_DB_REARM(cpr, cpr->cp_raw_cons); 29 } 30 31 /* ARM the default CQ/NQ at intervals of 1/8th of ring size */ 32 #define BNXT_DB_REARM_FACTOR 8 33 void bnxt_int_handler(void *param) 34 { 35 struct rte_eth_dev *eth_dev = (struct rte_eth_dev *)param; 36 struct bnxt *bp = eth_dev->data->dev_private; 37 uint32_t cons, raw_cons, cp_ring_size; 38 struct bnxt_cp_ring_info *cpr; 39 struct cmpl_base *cmp; 40 uint16_t cnt = 0; 41 42 43 if (bp == NULL) 44 return; 45 cpr = bp->async_cp_ring; 46 if (cpr == NULL) 47 return; 48 49 raw_cons = cpr->cp_raw_cons; 50 pthread_mutex_lock(&bp->def_cp_lock); 51 while (1) { 52 if (!cpr || !cpr->cp_ring_struct || !cpr->cp_db.doorbell) { 53 pthread_mutex_unlock(&bp->def_cp_lock); 54 return; 55 } 56 57 if (is_bnxt_in_error(bp)) { 58 pthread_mutex_unlock(&bp->def_cp_lock); 59 return; 60 } 61 62 cp_ring_size = cpr->cp_ring_struct->ring_size; 63 cons = RING_CMP(cpr->cp_ring_struct, raw_cons); 64 cmp = &cpr->cp_desc_ring[cons]; 65 66 if (!bnxt_cpr_cmp_valid(cmp, raw_cons, cp_ring_size)) 67 break; 68 69 bnxt_event_hwrm_resp_handler(bp, cmp); 70 raw_cons = NEXT_RAW_CMP(raw_cons); 71 if (++cnt >= cp_ring_size / BNXT_DB_REARM_FACTOR) { 72 bnxt_int_handler_rearm(bp, cpr, raw_cons); 73 cnt = 0; 74 } 75 } 76 77 /* cnt = 0 means no work or we rearmed already */ 78 if (cnt > 0) 79 bnxt_int_handler_rearm(bp, cpr, raw_cons); 80 81 pthread_mutex_unlock(&bp->def_cp_lock); 82 } 83 84 int bnxt_free_int(struct bnxt *bp) 85 { 86 struct rte_intr_handle *intr_handle = bp->pdev->intr_handle; 87 struct bnxt_irq *irq = bp->irq_tbl; 88 int rc = 0; 89 90 if (!irq) 91 return 0; 92 93 if (irq->requested) { 94 int count = 0; 95 96 /* 97 * Callback deregistration will fail with rc -EAGAIN if the 98 * callback is currently active. Retry every 50 ms until 99 * successful or 500 ms has elapsed. 100 */ 101 do { 102 rc = rte_intr_callback_unregister(intr_handle, 103 irq->handler, 104 bp->eth_dev); 105 if (rc >= 0) { 106 irq->requested = 0; 107 break; 108 } 109 rte_delay_ms(50); 110 } while (count++ < 10); 111 112 if (rc < 0) { 113 PMD_DRV_LOG_LINE(ERR, "irq cb unregister failed rc: %d", 114 rc); 115 return rc; 116 } 117 } 118 119 rte_free(bp->irq_tbl); 120 bp->irq_tbl = NULL; 121 122 return 0; 123 } 124 125 void bnxt_disable_int(struct bnxt *bp) 126 { 127 struct bnxt_cp_ring_info *cpr = bp->async_cp_ring; 128 129 if (BNXT_NUM_ASYNC_CPR(bp) == 0) 130 return; 131 132 if (is_bnxt_in_error(bp)) 133 return; 134 135 if (!cpr || !cpr->cp_db.doorbell) 136 return; 137 138 /* Only the default completion ring */ 139 if (BNXT_HAS_NQ(bp)) 140 bnxt_db_nq(cpr); 141 else 142 B_CP_DB_DISARM(cpr); 143 } 144 145 void bnxt_enable_int(struct bnxt *bp) 146 { 147 struct bnxt_cp_ring_info *cpr = bp->async_cp_ring; 148 149 if (BNXT_NUM_ASYNC_CPR(bp) == 0) 150 return; 151 152 if (!cpr || !cpr->cp_db.doorbell) 153 return; 154 155 /* Only the default completion ring */ 156 if (BNXT_HAS_NQ(bp)) 157 bnxt_db_nq_arm(cpr); 158 else 159 B_CP_DB_ARM(cpr); 160 } 161 162 int bnxt_setup_int(struct bnxt *bp) 163 { 164 uint16_t total_vecs; 165 const int len = sizeof(bp->irq_tbl[0].name); 166 int i; 167 168 /* DPDK host only supports 1 MSI-X vector */ 169 total_vecs = 1; 170 bp->irq_tbl = rte_calloc("bnxt_irq_tbl", total_vecs, 171 sizeof(struct bnxt_irq), 0); 172 if (bp->irq_tbl) { 173 for (i = 0; i < total_vecs; i++) { 174 bp->irq_tbl[i].vector_idx = i; 175 snprintf(bp->irq_tbl[i].name, len, 176 "%s-%d", bp->eth_dev->device->name, i); 177 bp->irq_tbl[i].handler = bnxt_int_handler; 178 } 179 } else { 180 PMD_DRV_LOG_LINE(ERR, "bnxt_irq_tbl setup failed"); 181 return -ENOMEM; 182 } 183 184 return 0; 185 } 186 187 int bnxt_request_int(struct bnxt *bp) 188 { 189 struct rte_intr_handle *intr_handle = bp->pdev->intr_handle; 190 struct bnxt_irq *irq = bp->irq_tbl; 191 int rc = 0; 192 193 if (!irq) 194 return 0; 195 196 if (!irq->requested) { 197 rc = rte_intr_callback_register(intr_handle, 198 irq->handler, 199 bp->eth_dev); 200 if (!rc) 201 irq->requested = 1; 202 } 203 204 #ifdef RTE_EXEC_ENV_FREEBSD 205 /** 206 * In FreeBSD OS, nic_uio does not support interrupts and 207 * interrupt register callback will fail. 208 */ 209 rc = 0; 210 #endif 211 212 return rc; 213 } 214