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