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(struct rte_intr_handle *intr_handle, 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 81 sfc_log_init(sa, "entry"); 82 83 if (sa->state != SFC_ADAPTER_STARTED && 84 sa->state != SFC_ADAPTER_STARTING && 85 sa->state != SFC_ADAPTER_STOPPING) { 86 sfc_log_init(sa, 87 "interrupt on stopped adapter, don't reenable"); 88 goto exit; 89 } 90 91 efx_intr_status_line(enp, &fatal, &qmask); 92 if (fatal) { 93 (void)efx_intr_disable(enp); 94 (void)efx_intr_fatal(enp); 95 sfc_err(sa, "fatal, interrupts disabled"); 96 goto exit; 97 } 98 99 if (qmask & (1 << sa->mgmt_evq_index)) 100 sfc_intr_handle_mgmt_evq(sa); 101 102 if (rte_intr_enable(intr_handle) != 0) 103 sfc_err(sa, "cannot reenable interrupts"); 104 105 sfc_log_init(sa, "done"); 106 107 exit: 108 if (lsc_seq != sa->port.lsc_seq) { 109 sfc_info(sa, "link status change event: link %s", 110 sa->eth_dev->data->dev_link.link_status ? 111 "UP" : "DOWN"); 112 _rte_eth_dev_callback_process(sa->eth_dev, 113 RTE_ETH_EVENT_INTR_LSC, NULL); 114 } 115 } 116 117 static void 118 sfc_intr_message_handler(struct rte_intr_handle *intr_handle, void *cb_arg) 119 { 120 struct sfc_adapter *sa = (struct sfc_adapter *)cb_arg; 121 efx_nic_t *enp = sa->nic; 122 boolean_t fatal; 123 unsigned int lsc_seq = sa->port.lsc_seq; 124 125 sfc_log_init(sa, "entry"); 126 127 if (sa->state != SFC_ADAPTER_STARTED && 128 sa->state != SFC_ADAPTER_STARTING && 129 sa->state != SFC_ADAPTER_STOPPING) { 130 sfc_log_init(sa, "adapter not-started, don't reenable"); 131 goto exit; 132 } 133 134 efx_intr_status_message(enp, sa->mgmt_evq_index, &fatal); 135 if (fatal) { 136 (void)efx_intr_disable(enp); 137 (void)efx_intr_fatal(enp); 138 sfc_err(sa, "fatal, interrupts disabled"); 139 goto exit; 140 } 141 142 sfc_intr_handle_mgmt_evq(sa); 143 144 if (rte_intr_enable(intr_handle) != 0) 145 sfc_err(sa, "cannot reenable interrupts"); 146 147 sfc_log_init(sa, "done"); 148 149 exit: 150 if (lsc_seq != sa->port.lsc_seq) { 151 sfc_info(sa, "link status change event"); 152 _rte_eth_dev_callback_process(sa->eth_dev, 153 RTE_ETH_EVENT_INTR_LSC, NULL); 154 } 155 } 156 157 int 158 sfc_intr_start(struct sfc_adapter *sa) 159 { 160 struct sfc_intr *intr = &sa->intr; 161 struct rte_intr_handle *intr_handle; 162 struct rte_pci_device *pci_dev; 163 int rc; 164 165 sfc_log_init(sa, "entry"); 166 167 /* 168 * The EFX common code event queue module depends on the interrupt 169 * module. Ensure that the interrupt module is always initialized 170 * (even if interrupts are not used). Status memory is required 171 * for Siena only and may be NULL for EF10. 172 */ 173 sfc_log_init(sa, "efx_intr_init"); 174 rc = efx_intr_init(sa->nic, intr->type, NULL); 175 if (rc != 0) 176 goto fail_intr_init; 177 178 pci_dev = SFC_DEV_TO_PCI(sa->eth_dev); 179 intr_handle = &pci_dev->intr_handle; 180 181 if (intr->handler != NULL) { 182 sfc_log_init(sa, "rte_intr_callback_register"); 183 rc = rte_intr_callback_register(intr_handle, intr->handler, 184 (void *)sa); 185 if (rc != 0) { 186 sfc_err(sa, 187 "cannot register interrupt handler (rc=%d)", 188 rc); 189 /* 190 * Convert error code from negative returned by RTE API 191 * to positive used in the driver. 192 */ 193 rc = -rc; 194 goto fail_rte_intr_cb_reg; 195 } 196 197 sfc_log_init(sa, "rte_intr_enable"); 198 rc = rte_intr_enable(intr_handle); 199 if (rc != 0) { 200 sfc_err(sa, "cannot enable interrupts (rc=%d)", rc); 201 /* 202 * Convert error code from negative returned by RTE API 203 * to positive used in the driver. 204 */ 205 rc = -rc; 206 goto fail_rte_intr_enable; 207 } 208 209 sfc_log_init(sa, "efx_intr_enable"); 210 efx_intr_enable(sa->nic); 211 } 212 213 sfc_log_init(sa, "done type=%u max_intr=%d nb_efd=%u vec=%p", 214 intr_handle->type, intr_handle->max_intr, 215 intr_handle->nb_efd, intr_handle->intr_vec); 216 return 0; 217 218 fail_rte_intr_enable: 219 rte_intr_callback_unregister(intr_handle, intr->handler, (void *)sa); 220 221 fail_rte_intr_cb_reg: 222 efx_intr_fini(sa->nic); 223 224 fail_intr_init: 225 sfc_log_init(sa, "failed %d", rc); 226 return rc; 227 } 228 229 void 230 sfc_intr_stop(struct sfc_adapter *sa) 231 { 232 struct sfc_intr *intr = &sa->intr; 233 struct rte_pci_device *pci_dev = SFC_DEV_TO_PCI(sa->eth_dev); 234 235 sfc_log_init(sa, "entry"); 236 237 if (intr->handler != NULL) { 238 struct rte_intr_handle *intr_handle; 239 int rc; 240 241 efx_intr_disable(sa->nic); 242 243 intr_handle = &pci_dev->intr_handle; 244 if (rte_intr_disable(intr_handle) != 0) 245 sfc_err(sa, "cannot disable interrupts"); 246 247 while ((rc = rte_intr_callback_unregister(intr_handle, 248 intr->handler, (void *)sa)) == -EAGAIN) 249 ; 250 if (rc != 1) 251 sfc_err(sa, 252 "cannot unregister interrupt handler %d", 253 rc); 254 } 255 256 efx_intr_fini(sa->nic); 257 258 sfc_log_init(sa, "done"); 259 } 260 261 int 262 sfc_intr_configure(struct sfc_adapter *sa) 263 { 264 struct sfc_intr *intr = &sa->intr; 265 266 sfc_log_init(sa, "entry"); 267 268 intr->handler = NULL; 269 intr->lsc_intr = (sa->eth_dev->data->dev_conf.intr_conf.lsc != 0); 270 if (!intr->lsc_intr) { 271 sfc_info(sa, "LSC tracking using interrupts is disabled"); 272 goto done; 273 } 274 275 switch (intr->type) { 276 case EFX_INTR_MESSAGE: 277 intr->handler = sfc_intr_message_handler; 278 break; 279 case EFX_INTR_LINE: 280 intr->handler = sfc_intr_line_handler; 281 break; 282 case EFX_INTR_INVALID: 283 sfc_warn(sa, "interrupts are not supported"); 284 break; 285 default: 286 sfc_panic(sa, "unexpected EFX interrupt type %u\n", intr->type); 287 break; 288 } 289 290 done: 291 sfc_log_init(sa, "done"); 292 return 0; 293 } 294 295 void 296 sfc_intr_close(struct sfc_adapter *sa) 297 { 298 sfc_log_init(sa, "entry"); 299 300 sfc_log_init(sa, "done"); 301 } 302 303 int 304 sfc_intr_attach(struct sfc_adapter *sa) 305 { 306 struct sfc_intr *intr = &sa->intr; 307 struct rte_pci_device *pci_dev = SFC_DEV_TO_PCI(sa->eth_dev); 308 309 sfc_log_init(sa, "entry"); 310 311 switch (pci_dev->intr_handle.type) { 312 #ifdef RTE_EXEC_ENV_LINUXAPP 313 case RTE_INTR_HANDLE_VFIO_LEGACY: 314 intr->type = EFX_INTR_LINE; 315 break; 316 case RTE_INTR_HANDLE_VFIO_MSI: 317 case RTE_INTR_HANDLE_VFIO_MSIX: 318 intr->type = EFX_INTR_MESSAGE; 319 break; 320 #endif 321 default: 322 intr->type = EFX_INTR_INVALID; 323 break; 324 } 325 326 sfc_log_init(sa, "done"); 327 return 0; 328 } 329 330 void 331 sfc_intr_detach(struct sfc_adapter *sa) 332 { 333 sfc_log_init(sa, "entry"); 334 335 sa->intr.type = EFX_INTR_INVALID; 336 337 sfc_log_init(sa, "done"); 338 } 339