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