1 /*- 2 * Copyright (c) 2016 Solarflare Communications Inc. 3 * All rights reserved. 4 * 5 * This software was jointly developed between OKTET Labs (under contract 6 * for Solarflare) and Solarflare Communications, Inc. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright notice, 12 * this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright notice, 14 * this list of conditions and the following disclaimer in the documentation 15 * and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 19 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 21 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 24 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 26 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 27 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 /* 31 * At the momemt of writing DPDK v16.07 has notion of two types of 32 * interrupts: LSC (link status change) and RXQ (receive indication). 33 * It allows to register interrupt callback for entire device which is 34 * not intended to be used for receive indication (i.e. link status 35 * change indication only). The handler has no information which HW 36 * interrupt has triggered it, so we don't know which event queue should 37 * be polled/reprimed (except qmask in the case of legacy line interrupt). 38 */ 39 40 #include <rte_common.h> 41 #include <rte_interrupts.h> 42 43 #include "efx.h" 44 45 #include "sfc.h" 46 #include "sfc_log.h" 47 #include "sfc_ev.h" 48 49 static void 50 sfc_intr_handle_mgmt_evq(struct sfc_adapter *sa) 51 { 52 struct sfc_evq *evq; 53 54 rte_spinlock_lock(&sa->mgmt_evq_lock); 55 56 evq = sa->evq_info[sa->mgmt_evq_index].evq; 57 58 if (evq->init_state != SFC_EVQ_STARTED) { 59 sfc_log_init(sa, "interrupt on stopped EVQ %u", evq->evq_index); 60 } else { 61 sfc_ev_qpoll(evq); 62 63 if (sfc_ev_qprime(evq) != 0) 64 sfc_err(sa, "cannot prime EVQ %u", evq->evq_index); 65 } 66 67 rte_spinlock_unlock(&sa->mgmt_evq_lock); 68 } 69 70 static void 71 sfc_intr_line_handler(struct rte_intr_handle *intr_handle, void *cb_arg) 72 { 73 struct sfc_adapter *sa = (struct sfc_adapter *)cb_arg; 74 efx_nic_t *enp = sa->nic; 75 boolean_t fatal; 76 uint32_t qmask; 77 unsigned int lsc_seq = sa->port.lsc_seq; 78 79 sfc_log_init(sa, "entry"); 80 81 if (sa->state != SFC_ADAPTER_STARTED && 82 sa->state != SFC_ADAPTER_STARTING && 83 sa->state != SFC_ADAPTER_STOPPING) { 84 sfc_log_init(sa, 85 "interrupt on stopped adapter, don't reenable"); 86 goto exit; 87 } 88 89 efx_intr_status_line(enp, &fatal, &qmask); 90 if (fatal) { 91 (void)efx_intr_disable(enp); 92 (void)efx_intr_fatal(enp); 93 sfc_err(sa, "fatal, interrupts disabled"); 94 goto exit; 95 } 96 97 if (qmask & (1 << sa->mgmt_evq_index)) 98 sfc_intr_handle_mgmt_evq(sa); 99 100 if (rte_intr_enable(intr_handle) != 0) 101 sfc_err(sa, "cannot reenable interrupts"); 102 103 sfc_log_init(sa, "done"); 104 105 exit: 106 if (lsc_seq != sa->port.lsc_seq) { 107 sfc_info(sa, "link status change event: link %s", 108 sa->eth_dev->data->dev_link.link_status ? 109 "UP" : "DOWN"); 110 _rte_eth_dev_callback_process(sa->eth_dev, 111 RTE_ETH_EVENT_INTR_LSC, NULL); 112 } 113 } 114 115 static void 116 sfc_intr_message_handler(struct rte_intr_handle *intr_handle, void *cb_arg) 117 { 118 struct sfc_adapter *sa = (struct sfc_adapter *)cb_arg; 119 efx_nic_t *enp = sa->nic; 120 boolean_t fatal; 121 unsigned int lsc_seq = sa->port.lsc_seq; 122 123 sfc_log_init(sa, "entry"); 124 125 if (sa->state != SFC_ADAPTER_STARTED && 126 sa->state != SFC_ADAPTER_STARTING && 127 sa->state != SFC_ADAPTER_STOPPING) { 128 sfc_log_init(sa, "adapter not-started, don't reenable"); 129 goto exit; 130 } 131 132 efx_intr_status_message(enp, sa->mgmt_evq_index, &fatal); 133 if (fatal) { 134 (void)efx_intr_disable(enp); 135 (void)efx_intr_fatal(enp); 136 sfc_err(sa, "fatal, interrupts disabled"); 137 goto exit; 138 } 139 140 sfc_intr_handle_mgmt_evq(sa); 141 142 if (rte_intr_enable(intr_handle) != 0) 143 sfc_err(sa, "cannot reenable interrupts"); 144 145 sfc_log_init(sa, "done"); 146 147 exit: 148 if (lsc_seq != sa->port.lsc_seq) { 149 sfc_info(sa, "link status change event"); 150 _rte_eth_dev_callback_process(sa->eth_dev, 151 RTE_ETH_EVENT_INTR_LSC, NULL); 152 } 153 } 154 155 int 156 sfc_intr_start(struct sfc_adapter *sa) 157 { 158 struct sfc_intr *intr = &sa->intr; 159 struct rte_intr_handle *intr_handle; 160 struct rte_pci_device *pci_dev; 161 int rc; 162 163 sfc_log_init(sa, "entry"); 164 165 /* 166 * The EFX common code event queue module depends on the interrupt 167 * module. Ensure that the interrupt module is always initialized 168 * (even if interrupts are not used). Status memory is required 169 * for Siena only and may be NULL for EF10. 170 */ 171 sfc_log_init(sa, "efx_intr_init"); 172 rc = efx_intr_init(sa->nic, intr->type, NULL); 173 if (rc != 0) 174 goto fail_intr_init; 175 176 pci_dev = SFC_DEV_TO_PCI(sa->eth_dev); 177 intr_handle = &pci_dev->intr_handle; 178 179 if (intr->handler != NULL) { 180 sfc_log_init(sa, "rte_intr_callback_register"); 181 rc = rte_intr_callback_register(intr_handle, intr->handler, 182 (void *)sa); 183 if (rc != 0) { 184 sfc_err(sa, 185 "cannot register interrupt handler (rc=%d)", 186 rc); 187 /* 188 * Convert error code from negative returned by RTE API 189 * to positive used in the driver. 190 */ 191 rc = -rc; 192 goto fail_rte_intr_cb_reg; 193 } 194 195 sfc_log_init(sa, "rte_intr_enable"); 196 rc = rte_intr_enable(intr_handle); 197 if (rc != 0) { 198 sfc_err(sa, "cannot enable interrupts (rc=%d)", rc); 199 /* 200 * Convert error code from negative returned by RTE API 201 * to positive used in the driver. 202 */ 203 rc = -rc; 204 goto fail_rte_intr_enable; 205 } 206 207 sfc_log_init(sa, "efx_intr_enable"); 208 efx_intr_enable(sa->nic); 209 } 210 211 sfc_log_init(sa, "done type=%u max_intr=%d nb_efd=%u vec=%p", 212 intr_handle->type, intr_handle->max_intr, 213 intr_handle->nb_efd, intr_handle->intr_vec); 214 return 0; 215 216 fail_rte_intr_enable: 217 rte_intr_callback_unregister(intr_handle, intr->handler, (void *)sa); 218 219 fail_rte_intr_cb_reg: 220 efx_intr_fini(sa->nic); 221 222 fail_intr_init: 223 sfc_log_init(sa, "failed %d", rc); 224 return rc; 225 } 226 227 void 228 sfc_intr_stop(struct sfc_adapter *sa) 229 { 230 struct sfc_intr *intr = &sa->intr; 231 struct rte_pci_device *pci_dev = SFC_DEV_TO_PCI(sa->eth_dev); 232 233 sfc_log_init(sa, "entry"); 234 235 if (intr->handler != NULL) { 236 struct rte_intr_handle *intr_handle; 237 int rc; 238 239 efx_intr_disable(sa->nic); 240 241 intr_handle = &pci_dev->intr_handle; 242 if (rte_intr_disable(intr_handle) != 0) 243 sfc_err(sa, "cannot disable interrupts"); 244 245 while ((rc = rte_intr_callback_unregister(intr_handle, 246 intr->handler, (void *)sa)) == -EAGAIN) 247 ; 248 if (rc != 1) 249 sfc_err(sa, 250 "cannot unregister interrupt handler %d", 251 rc); 252 } 253 254 efx_intr_fini(sa->nic); 255 256 sfc_log_init(sa, "done"); 257 } 258 259 int 260 sfc_intr_init(struct sfc_adapter *sa) 261 { 262 struct sfc_intr *intr = &sa->intr; 263 264 sfc_log_init(sa, "entry"); 265 266 intr->handler = NULL; 267 intr->lsc_intr = (sa->eth_dev->data->dev_conf.intr_conf.lsc != 0); 268 if (!intr->lsc_intr) { 269 sfc_info(sa, "LSC tracking using interrupts is disabled"); 270 goto done; 271 } 272 273 switch (intr->type) { 274 case EFX_INTR_MESSAGE: 275 intr->handler = sfc_intr_message_handler; 276 break; 277 case EFX_INTR_LINE: 278 intr->handler = sfc_intr_line_handler; 279 break; 280 case EFX_INTR_INVALID: 281 sfc_warn(sa, "interrupts are not supported"); 282 break; 283 default: 284 sfc_panic(sa, "unexpected EFX interrupt type %u\n", intr->type); 285 break; 286 } 287 288 done: 289 sfc_log_init(sa, "done"); 290 return 0; 291 } 292 293 void 294 sfc_intr_fini(struct sfc_adapter *sa) 295 { 296 sfc_log_init(sa, "entry"); 297 298 sfc_log_init(sa, "done"); 299 } 300 301 int 302 sfc_intr_attach(struct sfc_adapter *sa) 303 { 304 struct sfc_intr *intr = &sa->intr; 305 struct rte_pci_device *pci_dev = SFC_DEV_TO_PCI(sa->eth_dev); 306 307 sfc_log_init(sa, "entry"); 308 309 switch (pci_dev->intr_handle.type) { 310 #ifdef RTE_EXEC_ENV_LINUXAPP 311 case RTE_INTR_HANDLE_VFIO_LEGACY: 312 intr->type = EFX_INTR_LINE; 313 break; 314 case RTE_INTR_HANDLE_VFIO_MSI: 315 case RTE_INTR_HANDLE_VFIO_MSIX: 316 intr->type = EFX_INTR_MESSAGE; 317 break; 318 #endif 319 default: 320 intr->type = EFX_INTR_INVALID; 321 break; 322 } 323 324 sfc_log_init(sa, "done"); 325 return 0; 326 } 327 328 void 329 sfc_intr_detach(struct sfc_adapter *sa) 330 { 331 sfc_log_init(sa, "entry"); 332 333 sa->intr.type = EFX_INTR_INVALID; 334 335 sfc_log_init(sa, "done"); 336 } 337