diff options
| -rw-r--r-- | drivers/infiniband/hw/efa/efa_main.c | 533 |
1 files changed, 533 insertions, 0 deletions
diff --git a/drivers/infiniband/hw/efa/efa_main.c b/drivers/infiniband/hw/efa/efa_main.c new file mode 100644 index 000000000000..db974caf1eb1 --- /dev/null +++ b/drivers/infiniband/hw/efa/efa_main.c | |||
| @@ -0,0 +1,533 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause | ||
| 2 | /* | ||
| 3 | * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All rights reserved. | ||
| 4 | */ | ||
| 5 | |||
| 6 | #include <linux/module.h> | ||
| 7 | #include <linux/pci.h> | ||
| 8 | |||
| 9 | #include <rdma/ib_user_verbs.h> | ||
| 10 | |||
| 11 | #include "efa.h" | ||
| 12 | |||
| 13 | #define PCI_DEV_ID_EFA_VF 0xefa0 | ||
| 14 | |||
| 15 | static const struct pci_device_id efa_pci_tbl[] = { | ||
| 16 | { PCI_VDEVICE(AMAZON, PCI_DEV_ID_EFA_VF) }, | ||
| 17 | { } | ||
| 18 | }; | ||
| 19 | |||
| 20 | MODULE_AUTHOR("Amazon.com, Inc. or its affiliates"); | ||
| 21 | MODULE_LICENSE("Dual BSD/GPL"); | ||
| 22 | MODULE_DESCRIPTION(DEVICE_NAME); | ||
| 23 | MODULE_DEVICE_TABLE(pci, efa_pci_tbl); | ||
| 24 | |||
| 25 | #define EFA_REG_BAR 0 | ||
| 26 | #define EFA_MEM_BAR 2 | ||
| 27 | #define EFA_BASE_BAR_MASK (BIT(EFA_REG_BAR) | BIT(EFA_MEM_BAR)) | ||
| 28 | |||
| 29 | #define EFA_AENQ_ENABLED_GROUPS \ | ||
| 30 | (BIT(EFA_ADMIN_FATAL_ERROR) | BIT(EFA_ADMIN_WARNING) | \ | ||
| 31 | BIT(EFA_ADMIN_NOTIFICATION) | BIT(EFA_ADMIN_KEEP_ALIVE)) | ||
| 32 | |||
| 33 | static void efa_update_network_attr(struct efa_dev *dev, | ||
| 34 | struct efa_com_get_network_attr_result *network_attr) | ||
| 35 | { | ||
| 36 | memcpy(dev->addr, network_attr->addr, sizeof(network_attr->addr)); | ||
| 37 | dev->mtu = network_attr->mtu; | ||
| 38 | |||
| 39 | dev_dbg(&dev->pdev->dev, "Full address %pI6\n", dev->addr); | ||
| 40 | } | ||
| 41 | |||
| 42 | /* This handler will called for unknown event group or unimplemented handlers */ | ||
| 43 | static void unimplemented_aenq_handler(void *data, | ||
| 44 | struct efa_admin_aenq_entry *aenq_e) | ||
| 45 | { | ||
| 46 | struct efa_dev *dev = (struct efa_dev *)data; | ||
| 47 | |||
| 48 | ibdev_err(&dev->ibdev, | ||
| 49 | "Unknown event was received or event with unimplemented handler\n"); | ||
| 50 | } | ||
| 51 | |||
| 52 | static void efa_keep_alive(void *data, struct efa_admin_aenq_entry *aenq_e) | ||
| 53 | { | ||
| 54 | struct efa_dev *dev = (struct efa_dev *)data; | ||
| 55 | |||
| 56 | atomic64_inc(&dev->stats.keep_alive_rcvd); | ||
| 57 | } | ||
| 58 | |||
| 59 | static struct efa_aenq_handlers aenq_handlers = { | ||
| 60 | .handlers = { | ||
| 61 | [EFA_ADMIN_KEEP_ALIVE] = efa_keep_alive, | ||
| 62 | }, | ||
| 63 | .unimplemented_handler = unimplemented_aenq_handler | ||
| 64 | }; | ||
| 65 | |||
| 66 | static void efa_release_bars(struct efa_dev *dev, int bars_mask) | ||
| 67 | { | ||
| 68 | struct pci_dev *pdev = dev->pdev; | ||
| 69 | int release_bars; | ||
| 70 | |||
| 71 | release_bars = pci_select_bars(pdev, IORESOURCE_MEM) & bars_mask; | ||
| 72 | pci_release_selected_regions(pdev, release_bars); | ||
| 73 | } | ||
| 74 | |||
| 75 | static irqreturn_t efa_intr_msix_mgmnt(int irq, void *data) | ||
| 76 | { | ||
| 77 | struct efa_dev *dev = data; | ||
| 78 | |||
| 79 | efa_com_admin_q_comp_intr_handler(&dev->edev); | ||
| 80 | efa_com_aenq_intr_handler(&dev->edev, data); | ||
| 81 | |||
| 82 | return IRQ_HANDLED; | ||
| 83 | } | ||
| 84 | |||
| 85 | static int efa_request_mgmnt_irq(struct efa_dev *dev) | ||
| 86 | { | ||
| 87 | struct efa_irq *irq; | ||
| 88 | int err; | ||
| 89 | |||
| 90 | irq = &dev->admin_irq; | ||
| 91 | err = request_irq(irq->vector, irq->handler, 0, irq->name, | ||
| 92 | irq->data); | ||
| 93 | if (err) { | ||
| 94 | dev_err(&dev->pdev->dev, "Failed to request admin irq (%d)\n", | ||
| 95 | err); | ||
| 96 | return err; | ||
| 97 | } | ||
| 98 | |||
| 99 | dev_dbg(&dev->pdev->dev, "Set affinity hint of mgmnt irq to %*pbl (irq vector: %d)\n", | ||
| 100 | nr_cpumask_bits, &irq->affinity_hint_mask, irq->vector); | ||
| 101 | irq_set_affinity_hint(irq->vector, &irq->affinity_hint_mask); | ||
| 102 | |||
| 103 | return err; | ||
| 104 | } | ||
| 105 | |||
| 106 | static void efa_setup_mgmnt_irq(struct efa_dev *dev) | ||
| 107 | { | ||
| 108 | u32 cpu; | ||
| 109 | |||
| 110 | snprintf(dev->admin_irq.name, EFA_IRQNAME_SIZE, | ||
| 111 | "efa-mgmnt@pci:%s", pci_name(dev->pdev)); | ||
| 112 | dev->admin_irq.handler = efa_intr_msix_mgmnt; | ||
| 113 | dev->admin_irq.data = dev; | ||
| 114 | dev->admin_irq.vector = | ||
| 115 | pci_irq_vector(dev->pdev, dev->admin_msix_vector_idx); | ||
| 116 | cpu = cpumask_first(cpu_online_mask); | ||
| 117 | dev->admin_irq.cpu = cpu; | ||
| 118 | cpumask_set_cpu(cpu, | ||
| 119 | &dev->admin_irq.affinity_hint_mask); | ||
| 120 | dev_info(&dev->pdev->dev, "Setup irq:0x%p vector:%d name:%s\n", | ||
| 121 | &dev->admin_irq, | ||
| 122 | dev->admin_irq.vector, | ||
| 123 | dev->admin_irq.name); | ||
| 124 | } | ||
| 125 | |||
| 126 | static void efa_free_mgmnt_irq(struct efa_dev *dev) | ||
| 127 | { | ||
| 128 | struct efa_irq *irq; | ||
| 129 | |||
| 130 | irq = &dev->admin_irq; | ||
| 131 | irq_set_affinity_hint(irq->vector, NULL); | ||
| 132 | free_irq(irq->vector, irq->data); | ||
| 133 | } | ||
| 134 | |||
| 135 | static int efa_set_mgmnt_irq(struct efa_dev *dev) | ||
| 136 | { | ||
| 137 | efa_setup_mgmnt_irq(dev); | ||
| 138 | |||
| 139 | return efa_request_mgmnt_irq(dev); | ||
| 140 | } | ||
| 141 | |||
| 142 | static int efa_request_doorbell_bar(struct efa_dev *dev) | ||
| 143 | { | ||
| 144 | u8 db_bar_idx = dev->dev_attr.db_bar; | ||
| 145 | struct pci_dev *pdev = dev->pdev; | ||
| 146 | int bars; | ||
| 147 | int err; | ||
| 148 | |||
| 149 | if (!(BIT(db_bar_idx) & EFA_BASE_BAR_MASK)) { | ||
| 150 | bars = pci_select_bars(pdev, IORESOURCE_MEM) & BIT(db_bar_idx); | ||
| 151 | |||
| 152 | err = pci_request_selected_regions(pdev, bars, DRV_MODULE_NAME); | ||
| 153 | if (err) { | ||
| 154 | dev_err(&dev->pdev->dev, | ||
| 155 | "pci_request_selected_regions for bar %d failed %d\n", | ||
| 156 | db_bar_idx, err); | ||
| 157 | return err; | ||
| 158 | } | ||
| 159 | } | ||
| 160 | |||
| 161 | dev->db_bar_addr = pci_resource_start(dev->pdev, db_bar_idx); | ||
| 162 | dev->db_bar_len = pci_resource_len(dev->pdev, db_bar_idx); | ||
| 163 | |||
| 164 | return 0; | ||
| 165 | } | ||
| 166 | |||
| 167 | static void efa_release_doorbell_bar(struct efa_dev *dev) | ||
| 168 | { | ||
| 169 | if (!(BIT(dev->dev_attr.db_bar) & EFA_BASE_BAR_MASK)) | ||
| 170 | efa_release_bars(dev, BIT(dev->dev_attr.db_bar)); | ||
| 171 | } | ||
| 172 | |||
| 173 | static void efa_update_hw_hints(struct efa_dev *dev, | ||
| 174 | struct efa_com_get_hw_hints_result *hw_hints) | ||
| 175 | { | ||
| 176 | struct efa_com_dev *edev = &dev->edev; | ||
| 177 | |||
| 178 | if (hw_hints->mmio_read_timeout) | ||
| 179 | edev->mmio_read.mmio_read_timeout = | ||
| 180 | hw_hints->mmio_read_timeout * 1000; | ||
| 181 | |||
| 182 | if (hw_hints->poll_interval) | ||
| 183 | edev->aq.poll_interval = hw_hints->poll_interval; | ||
| 184 | |||
| 185 | if (hw_hints->admin_completion_timeout) | ||
| 186 | edev->aq.completion_timeout = | ||
| 187 | hw_hints->admin_completion_timeout; | ||
| 188 | } | ||
| 189 | |||
| 190 | static void efa_stats_init(struct efa_dev *dev) | ||
| 191 | { | ||
| 192 | atomic64_t *s = (atomic64_t *)&dev->stats; | ||
| 193 | int i; | ||
| 194 | |||
| 195 | for (i = 0; i < sizeof(dev->stats) / sizeof(*s); i++, s++) | ||
| 196 | atomic64_set(s, 0); | ||
| 197 | } | ||
| 198 | |||
| 199 | static const struct ib_device_ops efa_dev_ops = { | ||
| 200 | .alloc_pd = efa_alloc_pd, | ||
| 201 | .alloc_ucontext = efa_alloc_ucontext, | ||
| 202 | .create_ah = efa_create_ah, | ||
| 203 | .create_cq = efa_create_cq, | ||
| 204 | .create_qp = efa_create_qp, | ||
| 205 | .dealloc_pd = efa_dealloc_pd, | ||
| 206 | .dealloc_ucontext = efa_dealloc_ucontext, | ||
| 207 | .dereg_mr = efa_dereg_mr, | ||
| 208 | .destroy_ah = efa_destroy_ah, | ||
| 209 | .destroy_cq = efa_destroy_cq, | ||
| 210 | .destroy_qp = efa_destroy_qp, | ||
| 211 | .get_link_layer = efa_port_link_layer, | ||
| 212 | .get_port_immutable = efa_get_port_immutable, | ||
| 213 | .mmap = efa_mmap, | ||
| 214 | .modify_qp = efa_modify_qp, | ||
| 215 | .query_device = efa_query_device, | ||
| 216 | .query_gid = efa_query_gid, | ||
| 217 | .query_pkey = efa_query_pkey, | ||
| 218 | .query_port = efa_query_port, | ||
| 219 | .query_qp = efa_query_qp, | ||
| 220 | .reg_user_mr = efa_reg_mr, | ||
| 221 | |||
| 222 | INIT_RDMA_OBJ_SIZE(ib_ah, efa_ah, ibah), | ||
| 223 | INIT_RDMA_OBJ_SIZE(ib_pd, efa_pd, ibpd), | ||
| 224 | INIT_RDMA_OBJ_SIZE(ib_ucontext, efa_ucontext, ibucontext), | ||
| 225 | }; | ||
| 226 | |||
| 227 | static int efa_ib_device_add(struct efa_dev *dev) | ||
| 228 | { | ||
| 229 | struct efa_com_get_network_attr_result network_attr; | ||
| 230 | struct efa_com_get_hw_hints_result hw_hints; | ||
| 231 | struct pci_dev *pdev = dev->pdev; | ||
| 232 | int err; | ||
| 233 | |||
| 234 | efa_stats_init(dev); | ||
| 235 | |||
| 236 | err = efa_com_get_device_attr(&dev->edev, &dev->dev_attr); | ||
| 237 | if (err) | ||
| 238 | return err; | ||
| 239 | |||
| 240 | dev_dbg(&dev->pdev->dev, "Doorbells bar (%d)\n", dev->dev_attr.db_bar); | ||
| 241 | err = efa_request_doorbell_bar(dev); | ||
| 242 | if (err) | ||
| 243 | return err; | ||
| 244 | |||
| 245 | err = efa_com_get_network_attr(&dev->edev, &network_attr); | ||
| 246 | if (err) | ||
| 247 | goto err_release_doorbell_bar; | ||
| 248 | |||
| 249 | efa_update_network_attr(dev, &network_attr); | ||
| 250 | |||
| 251 | err = efa_com_get_hw_hints(&dev->edev, &hw_hints); | ||
| 252 | if (err) | ||
| 253 | goto err_release_doorbell_bar; | ||
| 254 | |||
| 255 | efa_update_hw_hints(dev, &hw_hints); | ||
| 256 | |||
| 257 | /* Try to enable all the available aenq groups */ | ||
| 258 | err = efa_com_set_aenq_config(&dev->edev, EFA_AENQ_ENABLED_GROUPS); | ||
| 259 | if (err) | ||
| 260 | goto err_release_doorbell_bar; | ||
| 261 | |||
| 262 | dev->ibdev.owner = THIS_MODULE; | ||
| 263 | dev->ibdev.node_type = RDMA_NODE_UNSPECIFIED; | ||
| 264 | dev->ibdev.phys_port_cnt = 1; | ||
| 265 | dev->ibdev.num_comp_vectors = 1; | ||
| 266 | dev->ibdev.dev.parent = &pdev->dev; | ||
| 267 | dev->ibdev.uverbs_abi_ver = EFA_UVERBS_ABI_VERSION; | ||
| 268 | |||
| 269 | dev->ibdev.uverbs_cmd_mask = | ||
| 270 | (1ull << IB_USER_VERBS_CMD_GET_CONTEXT) | | ||
| 271 | (1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) | | ||
| 272 | (1ull << IB_USER_VERBS_CMD_QUERY_PORT) | | ||
| 273 | (1ull << IB_USER_VERBS_CMD_ALLOC_PD) | | ||
| 274 | (1ull << IB_USER_VERBS_CMD_DEALLOC_PD) | | ||
| 275 | (1ull << IB_USER_VERBS_CMD_REG_MR) | | ||
| 276 | (1ull << IB_USER_VERBS_CMD_DEREG_MR) | | ||
| 277 | (1ull << IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL) | | ||
| 278 | (1ull << IB_USER_VERBS_CMD_CREATE_CQ) | | ||
| 279 | (1ull << IB_USER_VERBS_CMD_DESTROY_CQ) | | ||
| 280 | (1ull << IB_USER_VERBS_CMD_CREATE_QP) | | ||
| 281 | (1ull << IB_USER_VERBS_CMD_MODIFY_QP) | | ||
| 282 | (1ull << IB_USER_VERBS_CMD_QUERY_QP) | | ||
| 283 | (1ull << IB_USER_VERBS_CMD_DESTROY_QP) | | ||
| 284 | (1ull << IB_USER_VERBS_CMD_CREATE_AH) | | ||
| 285 | (1ull << IB_USER_VERBS_CMD_DESTROY_AH); | ||
| 286 | |||
| 287 | dev->ibdev.uverbs_ex_cmd_mask = | ||
| 288 | (1ull << IB_USER_VERBS_EX_CMD_QUERY_DEVICE); | ||
| 289 | |||
| 290 | dev->ibdev.driver_id = RDMA_DRIVER_EFA; | ||
| 291 | ib_set_device_ops(&dev->ibdev, &efa_dev_ops); | ||
| 292 | |||
| 293 | err = ib_register_device(&dev->ibdev, "efa_%d"); | ||
| 294 | if (err) | ||
| 295 | goto err_release_doorbell_bar; | ||
| 296 | |||
| 297 | ibdev_info(&dev->ibdev, "IB device registered\n"); | ||
| 298 | |||
| 299 | return 0; | ||
| 300 | |||
| 301 | err_release_doorbell_bar: | ||
| 302 | efa_release_doorbell_bar(dev); | ||
| 303 | return err; | ||
| 304 | } | ||
| 305 | |||
| 306 | static void efa_ib_device_remove(struct efa_dev *dev) | ||
| 307 | { | ||
| 308 | efa_com_dev_reset(&dev->edev, EFA_REGS_RESET_NORMAL); | ||
| 309 | ibdev_info(&dev->ibdev, "Unregister ib device\n"); | ||
| 310 | ib_unregister_device(&dev->ibdev); | ||
| 311 | efa_release_doorbell_bar(dev); | ||
| 312 | } | ||
| 313 | |||
| 314 | static void efa_disable_msix(struct efa_dev *dev) | ||
| 315 | { | ||
| 316 | pci_free_irq_vectors(dev->pdev); | ||
| 317 | } | ||
| 318 | |||
| 319 | static int efa_enable_msix(struct efa_dev *dev) | ||
| 320 | { | ||
| 321 | int msix_vecs, irq_num; | ||
| 322 | |||
| 323 | /* Reserve the max msix vectors we might need */ | ||
| 324 | msix_vecs = EFA_NUM_MSIX_VEC; | ||
| 325 | dev_dbg(&dev->pdev->dev, "Trying to enable MSI-X, vectors %d\n", | ||
| 326 | msix_vecs); | ||
| 327 | |||
| 328 | dev->admin_msix_vector_idx = EFA_MGMNT_MSIX_VEC_IDX; | ||
| 329 | irq_num = pci_alloc_irq_vectors(dev->pdev, msix_vecs, | ||
| 330 | msix_vecs, PCI_IRQ_MSIX); | ||
| 331 | |||
| 332 | if (irq_num < 0) { | ||
| 333 | dev_err(&dev->pdev->dev, "Failed to enable MSI-X. irq_num %d\n", | ||
| 334 | irq_num); | ||
| 335 | return -ENOSPC; | ||
| 336 | } | ||
| 337 | |||
| 338 | if (irq_num != msix_vecs) { | ||
| 339 | dev_err(&dev->pdev->dev, | ||
| 340 | "Allocated %d MSI-X (out of %d requested)\n", | ||
| 341 | irq_num, msix_vecs); | ||
| 342 | return -ENOSPC; | ||
| 343 | } | ||
| 344 | |||
| 345 | return 0; | ||
| 346 | } | ||
| 347 | |||
| 348 | static int efa_device_init(struct efa_com_dev *edev, struct pci_dev *pdev) | ||
| 349 | { | ||
| 350 | int dma_width; | ||
| 351 | int err; | ||
| 352 | |||
| 353 | err = efa_com_dev_reset(edev, EFA_REGS_RESET_NORMAL); | ||
| 354 | if (err) | ||
| 355 | return err; | ||
| 356 | |||
| 357 | err = efa_com_validate_version(edev); | ||
| 358 | if (err) | ||
| 359 | return err; | ||
| 360 | |||
| 361 | dma_width = efa_com_get_dma_width(edev); | ||
| 362 | if (dma_width < 0) { | ||
| 363 | err = dma_width; | ||
| 364 | return err; | ||
| 365 | } | ||
| 366 | |||
| 367 | err = pci_set_dma_mask(pdev, DMA_BIT_MASK(dma_width)); | ||
| 368 | if (err) { | ||
| 369 | dev_err(&pdev->dev, "pci_set_dma_mask failed %d\n", err); | ||
| 370 | return err; | ||
| 371 | } | ||
| 372 | |||
| 373 | err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(dma_width)); | ||
| 374 | if (err) { | ||
| 375 | dev_err(&pdev->dev, | ||
| 376 | "err_pci_set_consistent_dma_mask failed %d\n", | ||
| 377 | err); | ||
| 378 | return err; | ||
| 379 | } | ||
| 380 | |||
| 381 | return 0; | ||
| 382 | } | ||
| 383 | |||
| 384 | static struct efa_dev *efa_probe_device(struct pci_dev *pdev) | ||
| 385 | { | ||
| 386 | struct efa_com_dev *edev; | ||
| 387 | struct efa_dev *dev; | ||
| 388 | int bars; | ||
| 389 | int err; | ||
| 390 | |||
| 391 | err = pci_enable_device_mem(pdev); | ||
| 392 | if (err) { | ||
| 393 | dev_err(&pdev->dev, "pci_enable_device_mem() failed!\n"); | ||
| 394 | return ERR_PTR(err); | ||
| 395 | } | ||
| 396 | |||
| 397 | pci_set_master(pdev); | ||
| 398 | |||
| 399 | dev = ib_alloc_device(efa_dev, ibdev); | ||
| 400 | if (!dev) { | ||
| 401 | dev_err(&pdev->dev, "Device alloc failed\n"); | ||
| 402 | err = -ENOMEM; | ||
| 403 | goto err_disable_device; | ||
| 404 | } | ||
| 405 | |||
| 406 | pci_set_drvdata(pdev, dev); | ||
| 407 | edev = &dev->edev; | ||
| 408 | edev->efa_dev = dev; | ||
| 409 | edev->dmadev = &pdev->dev; | ||
| 410 | dev->pdev = pdev; | ||
| 411 | |||
| 412 | bars = pci_select_bars(pdev, IORESOURCE_MEM) & EFA_BASE_BAR_MASK; | ||
| 413 | err = pci_request_selected_regions(pdev, bars, DRV_MODULE_NAME); | ||
| 414 | if (err) { | ||
| 415 | dev_err(&pdev->dev, "pci_request_selected_regions failed %d\n", | ||
| 416 | err); | ||
| 417 | goto err_ibdev_destroy; | ||
| 418 | } | ||
| 419 | |||
| 420 | dev->reg_bar_addr = pci_resource_start(pdev, EFA_REG_BAR); | ||
| 421 | dev->reg_bar_len = pci_resource_len(pdev, EFA_REG_BAR); | ||
| 422 | dev->mem_bar_addr = pci_resource_start(pdev, EFA_MEM_BAR); | ||
| 423 | dev->mem_bar_len = pci_resource_len(pdev, EFA_MEM_BAR); | ||
| 424 | |||
| 425 | edev->reg_bar = devm_ioremap(&pdev->dev, | ||
| 426 | dev->reg_bar_addr, | ||
| 427 | dev->reg_bar_len); | ||
| 428 | if (!edev->reg_bar) { | ||
| 429 | dev_err(&pdev->dev, "Failed to remap register bar\n"); | ||
| 430 | err = -EFAULT; | ||
| 431 | goto err_release_bars; | ||
| 432 | } | ||
| 433 | |||
| 434 | err = efa_com_mmio_reg_read_init(edev); | ||
| 435 | if (err) { | ||
| 436 | dev_err(&pdev->dev, "Failed to init readless MMIO\n"); | ||
| 437 | goto err_iounmap; | ||
| 438 | } | ||
| 439 | |||
| 440 | err = efa_device_init(edev, pdev); | ||
| 441 | if (err) { | ||
| 442 | dev_err(&pdev->dev, "EFA device init failed\n"); | ||
| 443 | if (err == -ETIME) | ||
| 444 | err = -EPROBE_DEFER; | ||
| 445 | goto err_reg_read_destroy; | ||
| 446 | } | ||
| 447 | |||
| 448 | err = efa_enable_msix(dev); | ||
| 449 | if (err) | ||
| 450 | goto err_reg_read_destroy; | ||
| 451 | |||
| 452 | edev->aq.msix_vector_idx = dev->admin_msix_vector_idx; | ||
| 453 | edev->aenq.msix_vector_idx = dev->admin_msix_vector_idx; | ||
| 454 | |||
| 455 | err = efa_set_mgmnt_irq(dev); | ||
| 456 | if (err) | ||
| 457 | goto err_disable_msix; | ||
| 458 | |||
| 459 | err = efa_com_admin_init(edev, &aenq_handlers); | ||
| 460 | if (err) | ||
| 461 | goto err_free_mgmnt_irq; | ||
| 462 | |||
| 463 | return dev; | ||
| 464 | |||
| 465 | err_free_mgmnt_irq: | ||
| 466 | efa_free_mgmnt_irq(dev); | ||
| 467 | err_disable_msix: | ||
| 468 | efa_disable_msix(dev); | ||
| 469 | err_reg_read_destroy: | ||
| 470 | efa_com_mmio_reg_read_destroy(edev); | ||
| 471 | err_iounmap: | ||
| 472 | devm_iounmap(&pdev->dev, edev->reg_bar); | ||
| 473 | err_release_bars: | ||
| 474 | efa_release_bars(dev, EFA_BASE_BAR_MASK); | ||
| 475 | err_ibdev_destroy: | ||
| 476 | ib_dealloc_device(&dev->ibdev); | ||
| 477 | err_disable_device: | ||
| 478 | pci_disable_device(pdev); | ||
| 479 | return ERR_PTR(err); | ||
| 480 | } | ||
| 481 | |||
| 482 | static void efa_remove_device(struct pci_dev *pdev) | ||
| 483 | { | ||
| 484 | struct efa_dev *dev = pci_get_drvdata(pdev); | ||
| 485 | struct efa_com_dev *edev; | ||
| 486 | |||
| 487 | edev = &dev->edev; | ||
| 488 | efa_com_admin_destroy(edev); | ||
| 489 | efa_free_mgmnt_irq(dev); | ||
| 490 | efa_disable_msix(dev); | ||
| 491 | efa_com_mmio_reg_read_destroy(edev); | ||
| 492 | devm_iounmap(&pdev->dev, edev->reg_bar); | ||
| 493 | efa_release_bars(dev, EFA_BASE_BAR_MASK); | ||
| 494 | ib_dealloc_device(&dev->ibdev); | ||
| 495 | pci_disable_device(pdev); | ||
| 496 | } | ||
| 497 | |||
| 498 | static int efa_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | ||
| 499 | { | ||
| 500 | struct efa_dev *dev; | ||
| 501 | int err; | ||
| 502 | |||
| 503 | dev = efa_probe_device(pdev); | ||
| 504 | if (IS_ERR(dev)) | ||
| 505 | return PTR_ERR(dev); | ||
| 506 | |||
| 507 | err = efa_ib_device_add(dev); | ||
| 508 | if (err) | ||
| 509 | goto err_remove_device; | ||
| 510 | |||
| 511 | return 0; | ||
| 512 | |||
| 513 | err_remove_device: | ||
| 514 | efa_remove_device(pdev); | ||
| 515 | return err; | ||
| 516 | } | ||
| 517 | |||
| 518 | static void efa_remove(struct pci_dev *pdev) | ||
| 519 | { | ||
| 520 | struct efa_dev *dev = pci_get_drvdata(pdev); | ||
| 521 | |||
| 522 | efa_ib_device_remove(dev); | ||
| 523 | efa_remove_device(pdev); | ||
| 524 | } | ||
| 525 | |||
| 526 | static struct pci_driver efa_pci_driver = { | ||
| 527 | .name = DRV_MODULE_NAME, | ||
| 528 | .id_table = efa_pci_tbl, | ||
| 529 | .probe = efa_probe, | ||
| 530 | .remove = efa_remove, | ||
| 531 | }; | ||
| 532 | |||
| 533 | module_pci_driver(efa_pci_driver); | ||
