Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net/mlx5: Introduce API for bulk request and release of IRQs

Currently IRQs are requested one by one. To balance spreading IRQs
among cpus using such scheme requires remembering cpu mask for the
cpus used for a given device. This complicates the IRQ allocation
scheme in subsequent patch.

Hence, prepare the code for bulk IRQs allocation. This enables
spreading IRQs among cpus in subsequent patch.

Signed-off-by: Shay Drory <shayd@nvidia.com>
Reviewed-by: Parav Pandit <parav@nvidia.com>
Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>

authored by

Shay Drory and committed by
Saeed Mahameed
79b60ca8 424544df

+135 -47
-6
drivers/infiniband/hw/mlx5/odp.c
··· 1541 1541 1542 1542 eq->irq_nb.notifier_call = mlx5_ib_eq_pf_int; 1543 1543 param = (struct mlx5_eq_param) { 1544 - .irq_index = MLX5_IRQ_EQ_CTRL, 1545 1544 .nent = MLX5_IB_NUM_PF_EQE, 1546 1545 }; 1547 1546 param.mask[0] = 1ull << MLX5_EVENT_TYPE_PAGE_FAULT; 1548 - if (!zalloc_cpumask_var(&param.affinity, GFP_KERNEL)) { 1549 - err = -ENOMEM; 1550 - goto err_wq; 1551 - } 1552 1547 eq->core = mlx5_eq_create_generic(dev->mdev, &param); 1553 - free_cpumask_var(param.affinity); 1554 1548 if (IS_ERR(eq->core)) { 1555 1549 err = PTR_ERR(eq->core); 1556 1550 goto err_wq;
+65 -33
drivers/net/ethernet/mellanox/mlx5/core/eq.c
··· 59 59 struct mutex lock; /* sync async eqs creations */ 60 60 int num_comp_eqs; 61 61 struct mlx5_irq_table *irq_table; 62 + struct mlx5_irq **comp_irqs; 63 + struct mlx5_irq *ctrl_irq; 62 64 #ifdef CONFIG_RFS_ACCEL 63 65 struct cpu_rmap *rmap; 64 66 #endif ··· 268 266 u32 out[MLX5_ST_SZ_DW(create_eq_out)] = {0}; 269 267 u8 log_eq_stride = ilog2(MLX5_EQE_SIZE); 270 268 struct mlx5_priv *priv = &dev->priv; 271 - u16 vecidx = param->irq_index; 272 269 __be64 *pas; 270 + u16 vecidx; 273 271 void *eqc; 274 272 int inlen; 275 273 u32 *in; ··· 291 289 mlx5_init_fbc(eq->frag_buf.frags, log_eq_stride, log_eq_size, &eq->fbc); 292 290 init_eq_buf(eq); 293 291 294 - if (vecidx == MLX5_IRQ_EQ_CTRL) 295 - eq->irq = mlx5_ctrl_irq_request(dev); 296 - else 297 - eq->irq = mlx5_irq_request(dev, vecidx, param->affinity); 298 - if (IS_ERR(eq->irq)) { 299 - err = PTR_ERR(eq->irq); 300 - goto err_buf; 301 - } 302 - 292 + eq->irq = param->irq; 303 293 vecidx = mlx5_irq_get_index(eq->irq); 294 + 304 295 inlen = MLX5_ST_SZ_BYTES(create_eq_in) + 305 296 MLX5_FLD_SZ_BYTES(create_eq_in, pas[0]) * eq->frag_buf.npages; 306 297 307 298 in = kvzalloc(inlen, GFP_KERNEL); 308 299 if (!in) { 309 300 err = -ENOMEM; 310 - goto err_irq; 301 + goto err_buf; 311 302 } 312 303 313 304 pas = (__be64 *)MLX5_ADDR_OF(create_eq_in, in, pas); ··· 344 349 err_in: 345 350 kvfree(in); 346 351 347 - err_irq: 348 - mlx5_irq_release(eq->irq); 349 352 err_buf: 350 353 mlx5_frag_buf_free(dev, &eq->frag_buf); 351 354 return err; ··· 397 404 if (err) 398 405 mlx5_core_warn(dev, "failed to destroy a previously created eq: eqn %d\n", 399 406 eq->eqn); 400 - mlx5_irq_release(eq->irq); 401 407 402 408 mlx5_frag_buf_free(dev, &eq->frag_buf); 403 409 return err; ··· 589 597 590 598 eq->irq_nb.notifier_call = mlx5_eq_async_int; 591 599 spin_lock_init(&eq->lock); 592 - if (!zalloc_cpumask_var(&param->affinity, GFP_KERNEL)) 593 - return -ENOMEM; 594 600 595 601 err = create_async_eq(dev, &eq->core, param); 596 - free_cpumask_var(param->affinity); 597 602 if (err) { 598 603 mlx5_core_warn(dev, "failed to create %s EQ %d\n", name, err); 599 604 return err; ··· 635 646 struct mlx5_eq_param param = {}; 636 647 int err; 637 648 649 + /* All the async_eqs are using single IRQ, request one IRQ and share its 650 + * index among all the async_eqs of this device. 651 + */ 652 + table->ctrl_irq = mlx5_ctrl_irq_request(dev); 653 + if (IS_ERR(table->ctrl_irq)) 654 + return PTR_ERR(table->ctrl_irq); 655 + 638 656 MLX5_NB_INIT(&table->cq_err_nb, cq_err_event_notifier, CQ_ERROR); 639 657 mlx5_eq_notifier_register(dev, &table->cq_err_nb); 640 658 641 659 param = (struct mlx5_eq_param) { 642 - .irq_index = MLX5_IRQ_EQ_CTRL, 660 + .irq = table->ctrl_irq, 643 661 .nent = MLX5_NUM_CMD_EQE, 644 662 .mask[0] = 1ull << MLX5_EVENT_TYPE_CMD, 645 663 }; ··· 659 663 mlx5_cmd_allowed_opcode(dev, CMD_ALLOWED_OPCODE_ALL); 660 664 661 665 param = (struct mlx5_eq_param) { 662 - .irq_index = MLX5_IRQ_EQ_CTRL, 666 + .irq = table->ctrl_irq, 663 667 .nent = async_eq_depth_devlink_param_get(dev), 664 668 }; 665 669 ··· 669 673 goto err2; 670 674 671 675 param = (struct mlx5_eq_param) { 672 - .irq_index = MLX5_IRQ_EQ_CTRL, 676 + .irq = table->ctrl_irq, 673 677 .nent = /* TODO: sriov max_vf + */ 1, 674 678 .mask[0] = 1ull << MLX5_EVENT_TYPE_PAGE_REQUEST, 675 679 }; ··· 688 692 err1: 689 693 mlx5_cmd_allowed_opcode(dev, CMD_ALLOWED_OPCODE_ALL); 690 694 mlx5_eq_notifier_unregister(dev, &table->cq_err_nb); 695 + mlx5_ctrl_irq_release(table->ctrl_irq); 691 696 return err; 692 697 } 693 698 ··· 703 706 cleanup_async_eq(dev, &table->cmd_eq, "cmd"); 704 707 mlx5_cmd_allowed_opcode(dev, CMD_ALLOWED_OPCODE_ALL); 705 708 mlx5_eq_notifier_unregister(dev, &table->cq_err_nb); 709 + mlx5_ctrl_irq_release(table->ctrl_irq); 706 710 } 707 711 708 712 struct mlx5_eq *mlx5_get_async_eq(struct mlx5_core_dev *dev) ··· 731 733 struct mlx5_eq *eq = kvzalloc(sizeof(*eq), GFP_KERNEL); 732 734 int err; 733 735 734 - if (!cpumask_available(param->affinity)) 735 - return ERR_PTR(-EINVAL); 736 - 737 736 if (!eq) 738 737 return ERR_PTR(-ENOMEM); 739 738 739 + param->irq = dev->priv.eq_table->ctrl_irq; 740 740 err = create_async_eq(dev, eq, param); 741 741 if (err) { 742 742 kvfree(eq); ··· 794 798 } 795 799 EXPORT_SYMBOL(mlx5_eq_update_ci); 796 800 801 + static void comp_irqs_release(struct mlx5_core_dev *dev) 802 + { 803 + struct mlx5_eq_table *table = dev->priv.eq_table; 804 + 805 + mlx5_irqs_release_vectors(table->comp_irqs, table->num_comp_eqs); 806 + kfree(table->comp_irqs); 807 + } 808 + 809 + static int comp_irqs_request(struct mlx5_core_dev *dev) 810 + { 811 + struct mlx5_eq_table *table = dev->priv.eq_table; 812 + int ncomp_eqs = table->num_comp_eqs; 813 + u16 *cpus; 814 + int ret; 815 + int i; 816 + 817 + ncomp_eqs = table->num_comp_eqs; 818 + table->comp_irqs = kcalloc(ncomp_eqs, sizeof(*table->comp_irqs), GFP_KERNEL); 819 + if (!table->comp_irqs) 820 + return -ENOMEM; 821 + 822 + cpus = kcalloc(ncomp_eqs, sizeof(*cpus), GFP_KERNEL); 823 + if (!cpus) { 824 + ret = -ENOMEM; 825 + goto free_irqs; 826 + } 827 + for (i = 0; i < ncomp_eqs; i++) 828 + cpus[i] = cpumask_local_spread(i, dev->priv.numa_node); 829 + ret = mlx5_irqs_request_vectors(dev, cpus, ncomp_eqs, table->comp_irqs); 830 + kfree(cpus); 831 + if (ret < 0) 832 + goto free_irqs; 833 + return ret; 834 + 835 + free_irqs: 836 + kfree(table->comp_irqs); 837 + return ret; 838 + } 839 + 797 840 static void destroy_comp_eqs(struct mlx5_core_dev *dev) 798 841 { 799 842 struct mlx5_eq_table *table = dev->priv.eq_table; ··· 847 812 tasklet_disable(&eq->tasklet_ctx.task); 848 813 kfree(eq); 849 814 } 815 + comp_irqs_release(dev); 850 816 } 851 817 852 818 static u16 comp_eq_depth_devlink_param_get(struct mlx5_core_dev *dev) ··· 874 838 int err; 875 839 int i; 876 840 841 + ncomp_eqs = comp_irqs_request(dev); 842 + if (ncomp_eqs < 0) 843 + return ncomp_eqs; 877 844 INIT_LIST_HEAD(&table->comp_eqs_list); 878 - ncomp_eqs = table->num_comp_eqs; 879 845 nent = comp_eq_depth_devlink_param_get(dev); 880 846 for (i = 0; i < ncomp_eqs; i++) { 881 847 struct mlx5_eq_param param = {}; 882 - int vecidx = i; 883 848 884 849 eq = kzalloc(sizeof(*eq), GFP_KERNEL); 885 850 if (!eq) { ··· 895 858 896 859 eq->irq_nb.notifier_call = mlx5_eq_comp_int; 897 860 param = (struct mlx5_eq_param) { 898 - .irq_index = vecidx, 861 + .irq = table->comp_irqs[i], 899 862 .nent = nent, 900 863 }; 901 864 902 - if (!zalloc_cpumask_var(&param.affinity, GFP_KERNEL)) { 903 - err = -ENOMEM; 904 - goto clean_eq; 905 - } 906 - cpumask_set_cpu(cpumask_local_spread(i, dev->priv.numa_node), 907 - param.affinity); 908 865 err = create_map_eq(dev, &eq->core, &param); 909 - free_cpumask_var(param.affinity); 910 866 if (err) 911 867 goto clean_eq; 912 868 err = mlx5_eq_enable(dev, &eq->core, &eq->irq_nb); ··· 913 883 list_add_tail(&eq->list, &table->comp_eqs_list); 914 884 } 915 885 886 + table->num_comp_eqs = ncomp_eqs; 916 887 return 0; 888 + 917 889 clean_eq: 918 890 kfree(eq); 919 891 clean:
+4 -1
drivers/net/ethernet/mellanox/mlx5/core/mlx5_irq.h
··· 23 23 int mlx5_get_default_msix_vec_count(struct mlx5_core_dev *dev, int num_vfs); 24 24 25 25 struct mlx5_irq *mlx5_ctrl_irq_request(struct mlx5_core_dev *dev); 26 + void mlx5_ctrl_irq_release(struct mlx5_irq *ctrl_irq); 26 27 struct mlx5_irq *mlx5_irq_request(struct mlx5_core_dev *dev, u16 vecidx, 27 28 struct cpumask *affinity); 28 - void mlx5_irq_release(struct mlx5_irq *irq); 29 + int mlx5_irqs_request_vectors(struct mlx5_core_dev *dev, u16 *cpus, int nirqs, 30 + struct mlx5_irq **irqs); 31 + void mlx5_irqs_release_vectors(struct mlx5_irq **irqs, int nirqs); 29 32 int mlx5_irq_attach_nb(struct mlx5_irq *irq, struct notifier_block *nb); 30 33 int mlx5_irq_detach_nb(struct mlx5_irq *irq, struct notifier_block *nb); 31 34 struct cpumask *mlx5_irq_get_affinity_mask(struct mlx5_irq *irq);
+64 -5
drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c
··· 342 342 } 343 343 344 344 /** 345 - * mlx5_irq_release - release an IRQ back to the system. 346 - * @irq: irq to be released. 345 + * mlx5_irqs_release - release one or more IRQs back to the system. 346 + * @irqs: IRQs to be released. 347 + * @nirqs: number of IRQs to be released. 347 348 */ 348 - void mlx5_irq_release(struct mlx5_irq *irq) 349 + static void mlx5_irqs_release(struct mlx5_irq **irqs, int nirqs) 349 350 { 350 - synchronize_irq(irq->irqn); 351 - irq_put(irq); 351 + int i; 352 + 353 + for (i = 0; i < nirqs; i++) { 354 + synchronize_irq(irqs[i]->irqn); 355 + irq_put(irqs[i]); 356 + } 357 + } 358 + 359 + /** 360 + * mlx5_ctrl_irq_release - release a ctrl IRQ back to the system. 361 + * @ctrl_irq: ctrl IRQ to be released. 362 + */ 363 + void mlx5_ctrl_irq_release(struct mlx5_irq *ctrl_irq) 364 + { 365 + mlx5_irqs_release(&ctrl_irq, 1); 352 366 } 353 367 354 368 /** ··· 435 421 irq->irqn, cpumask_pr_args(affinity), 436 422 irq->refcount / MLX5_EQ_REFS_PER_IRQ); 437 423 return irq; 424 + } 425 + 426 + /** 427 + * mlx5_irqs_release_vectors - release one or more IRQs back to the system. 428 + * @irqs: IRQs to be released. 429 + * @nirqs: number of IRQs to be released. 430 + */ 431 + void mlx5_irqs_release_vectors(struct mlx5_irq **irqs, int nirqs) 432 + { 433 + mlx5_irqs_release(irqs, nirqs); 434 + } 435 + 436 + /** 437 + * mlx5_irqs_request_vectors - request one or more IRQs for mlx5 device. 438 + * @dev: mlx5 device that is requesting the IRQs. 439 + * @cpus: CPUs array for binding the IRQs 440 + * @nirqs: number of IRQs to request. 441 + * @irqs: an output array of IRQs pointers. 442 + * 443 + * Each IRQ is bound to at most 1 CPU. 444 + * This function is requests nirqs IRQs, starting from @vecidx. 445 + * 446 + * This function returns the number of IRQs requested, (which might be smaller than 447 + * @nirqs), if successful, or a negative error code in case of an error. 448 + */ 449 + int mlx5_irqs_request_vectors(struct mlx5_core_dev *dev, u16 *cpus, int nirqs, 450 + struct mlx5_irq **irqs) 451 + { 452 + cpumask_var_t req_mask; 453 + struct mlx5_irq *irq; 454 + int i; 455 + 456 + if (!zalloc_cpumask_var(&req_mask, GFP_KERNEL)) 457 + return -ENOMEM; 458 + for (i = 0; i < nirqs; i++) { 459 + cpumask_set_cpu(cpus[i], req_mask); 460 + irq = mlx5_irq_request(dev, i, req_mask); 461 + if (IS_ERR(irq)) 462 + break; 463 + cpumask_clear(req_mask); 464 + irqs[i] = irq; 465 + } 466 + 467 + free_cpumask_var(req_mask); 468 + return i ? i : PTR_ERR(irq); 438 469 } 439 470 440 471 static struct mlx5_irq_pool *
+2 -2
include/linux/mlx5/eq.h
··· 9 9 #define MLX5_NUM_SPARE_EQE (0x80) 10 10 11 11 struct mlx5_eq; 12 + struct mlx5_irq; 12 13 struct mlx5_core_dev; 13 14 14 15 struct mlx5_eq_param { 15 - u8 irq_index; 16 16 int nent; 17 17 u64 mask[4]; 18 - cpumask_var_t affinity; 18 + struct mlx5_irq *irq; 19 19 }; 20 20 21 21 struct mlx5_eq *