| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Huawei HiNIC PCI Express Linux driver |
|---|
| 3 | 4 | * Copyright(c) 2017 Huawei Technologies Co., Ltd |
|---|
| 4 | | - * |
|---|
| 5 | | - * This program is free software; you can redistribute it and/or modify it |
|---|
| 6 | | - * under the terms and conditions of the GNU General Public License, |
|---|
| 7 | | - * version 2, as published by the Free Software Foundation. |
|---|
| 8 | | - * |
|---|
| 9 | | - * This program is distributed in the hope it will be useful, but WITHOUT |
|---|
| 10 | | - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|---|
| 11 | | - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|---|
| 12 | | - * for more details. |
|---|
| 13 | | - * |
|---|
| 14 | 5 | */ |
|---|
| 15 | 6 | |
|---|
| 16 | 7 | #include <linux/kernel.h> |
|---|
| .. | .. |
|---|
| 74 | 65 | ((void *)((cmdq_pages)->shadow_page_vaddr) \ |
|---|
| 75 | 66 | + (wq)->block_idx * CMDQ_BLOCK_SIZE) |
|---|
| 76 | 67 | |
|---|
| 77 | | -#define WQE_PAGE_OFF(wq, idx) (((idx) & ((wq)->num_wqebbs_per_page - 1)) * \ |
|---|
| 78 | | - (wq)->wqebb_size) |
|---|
| 79 | | - |
|---|
| 80 | | -#define WQE_PAGE_NUM(wq, idx) (((idx) / ((wq)->num_wqebbs_per_page)) \ |
|---|
| 81 | | - & ((wq)->num_q_pages - 1)) |
|---|
| 82 | | - |
|---|
| 83 | 68 | #define WQ_PAGE_ADDR(wq, idx) \ |
|---|
| 84 | 69 | ((wq)->shadow_block_vaddr[WQE_PAGE_NUM(wq, idx)]) |
|---|
| 85 | 70 | |
|---|
| .. | .. |
|---|
| 93 | 78 | (((unsigned long)(wqe) - (unsigned long)(wq)->shadow_wqe) \ |
|---|
| 94 | 79 | / (wq)->max_wqe_size) |
|---|
| 95 | 80 | |
|---|
| 81 | +static inline int WQE_PAGE_OFF(struct hinic_wq *wq, u16 idx) |
|---|
| 82 | +{ |
|---|
| 83 | + return (((idx) & ((wq)->num_wqebbs_per_page - 1)) |
|---|
| 84 | + << (wq)->wqebb_size_shift); |
|---|
| 85 | +} |
|---|
| 86 | + |
|---|
| 87 | +static inline int WQE_PAGE_NUM(struct hinic_wq *wq, u16 idx) |
|---|
| 88 | +{ |
|---|
| 89 | + return (((idx) >> ((wq)->wqebbs_per_page_shift)) |
|---|
| 90 | + & ((wq)->num_q_pages - 1)); |
|---|
| 91 | +} |
|---|
| 96 | 92 | /** |
|---|
| 97 | 93 | * queue_alloc_page - allocate page for Queue |
|---|
| 98 | 94 | * @hwif: HW interface for allocating DMA |
|---|
| .. | .. |
|---|
| 109 | 105 | struct pci_dev *pdev = hwif->pdev; |
|---|
| 110 | 106 | dma_addr_t dma_addr; |
|---|
| 111 | 107 | |
|---|
| 112 | | - *vaddr = dma_zalloc_coherent(&pdev->dev, page_sz, &dma_addr, |
|---|
| 113 | | - GFP_KERNEL); |
|---|
| 108 | + *vaddr = dma_alloc_coherent(&pdev->dev, page_sz, &dma_addr, |
|---|
| 109 | + GFP_KERNEL); |
|---|
| 114 | 110 | if (!*vaddr) { |
|---|
| 115 | 111 | dev_err(&pdev->dev, "Failed to allocate dma for wqs page\n"); |
|---|
| 116 | 112 | return -ENOMEM; |
|---|
| .. | .. |
|---|
| 196 | 192 | { |
|---|
| 197 | 193 | struct hinic_hwif *hwif = wqs->hwif; |
|---|
| 198 | 194 | struct pci_dev *pdev = hwif->pdev; |
|---|
| 199 | | - size_t size; |
|---|
| 200 | 195 | |
|---|
| 201 | | - size = wqs->num_pages * sizeof(*wqs->page_paddr); |
|---|
| 202 | | - wqs->page_paddr = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); |
|---|
| 196 | + wqs->page_paddr = devm_kcalloc(&pdev->dev, wqs->num_pages, |
|---|
| 197 | + sizeof(*wqs->page_paddr), GFP_KERNEL); |
|---|
| 203 | 198 | if (!wqs->page_paddr) |
|---|
| 204 | 199 | return -ENOMEM; |
|---|
| 205 | 200 | |
|---|
| 206 | | - size = wqs->num_pages * sizeof(*wqs->page_vaddr); |
|---|
| 207 | | - wqs->page_vaddr = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); |
|---|
| 201 | + wqs->page_vaddr = devm_kcalloc(&pdev->dev, wqs->num_pages, |
|---|
| 202 | + sizeof(*wqs->page_vaddr), GFP_KERNEL); |
|---|
| 208 | 203 | if (!wqs->page_vaddr) |
|---|
| 209 | 204 | goto err_page_vaddr; |
|---|
| 210 | 205 | |
|---|
| 211 | | - size = wqs->num_pages * sizeof(*wqs->shadow_page_vaddr); |
|---|
| 212 | | - wqs->shadow_page_vaddr = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); |
|---|
| 206 | + wqs->shadow_page_vaddr = devm_kcalloc(&pdev->dev, wqs->num_pages, |
|---|
| 207 | + sizeof(*wqs->shadow_page_vaddr), |
|---|
| 208 | + GFP_KERNEL); |
|---|
| 213 | 209 | if (!wqs->shadow_page_vaddr) |
|---|
| 214 | 210 | goto err_page_shadow_vaddr; |
|---|
| 215 | 211 | |
|---|
| .. | .. |
|---|
| 382 | 378 | { |
|---|
| 383 | 379 | struct hinic_hwif *hwif = wq->hwif; |
|---|
| 384 | 380 | struct pci_dev *pdev = hwif->pdev; |
|---|
| 385 | | - size_t size; |
|---|
| 386 | 381 | |
|---|
| 387 | | - size = wq->num_q_pages * wq->max_wqe_size; |
|---|
| 388 | | - wq->shadow_wqe = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); |
|---|
| 382 | + wq->shadow_wqe = devm_kcalloc(&pdev->dev, wq->num_q_pages, |
|---|
| 383 | + wq->max_wqe_size, GFP_KERNEL); |
|---|
| 389 | 384 | if (!wq->shadow_wqe) |
|---|
| 390 | 385 | return -ENOMEM; |
|---|
| 391 | 386 | |
|---|
| 392 | | - size = wq->num_q_pages * sizeof(wq->prod_idx); |
|---|
| 393 | | - wq->shadow_idx = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); |
|---|
| 387 | + wq->shadow_idx = devm_kcalloc(&pdev->dev, wq->num_q_pages, |
|---|
| 388 | + sizeof(*wq->shadow_idx), GFP_KERNEL); |
|---|
| 394 | 389 | if (!wq->shadow_idx) |
|---|
| 395 | 390 | goto err_shadow_idx; |
|---|
| 396 | 391 | |
|---|
| .. | .. |
|---|
| 477 | 472 | u64 *paddr = &wq->block_vaddr[i]; |
|---|
| 478 | 473 | dma_addr_t dma_addr; |
|---|
| 479 | 474 | |
|---|
| 480 | | - *vaddr = dma_zalloc_coherent(&pdev->dev, wq->wq_page_size, |
|---|
| 481 | | - &dma_addr, GFP_KERNEL); |
|---|
| 475 | + *vaddr = dma_alloc_coherent(&pdev->dev, wq->wq_page_size, |
|---|
| 476 | + &dma_addr, GFP_KERNEL); |
|---|
| 482 | 477 | if (!*vaddr) { |
|---|
| 483 | 478 | dev_err(&pdev->dev, "Failed to allocate wq page\n"); |
|---|
| 484 | 479 | goto err_alloc_wq_pages; |
|---|
| .. | .. |
|---|
| 507 | 502 | * Return 0 - Success, negative - Failure |
|---|
| 508 | 503 | **/ |
|---|
| 509 | 504 | int hinic_wq_allocate(struct hinic_wqs *wqs, struct hinic_wq *wq, |
|---|
| 510 | | - u16 wqebb_size, u16 wq_page_size, u16 q_depth, |
|---|
| 505 | + u16 wqebb_size, u32 wq_page_size, u16 q_depth, |
|---|
| 511 | 506 | u16 max_wqe_size) |
|---|
| 512 | 507 | { |
|---|
| 513 | 508 | struct hinic_hwif *hwif = wqs->hwif; |
|---|
| 514 | 509 | struct pci_dev *pdev = hwif->pdev; |
|---|
| 515 | 510 | u16 num_wqebbs_per_page; |
|---|
| 511 | + u16 wqebb_size_shift; |
|---|
| 516 | 512 | int err; |
|---|
| 517 | 513 | |
|---|
| 518 | | - if (wqebb_size == 0) { |
|---|
| 519 | | - dev_err(&pdev->dev, "wqebb_size must be > 0\n"); |
|---|
| 514 | + if (!is_power_of_2(wqebb_size)) { |
|---|
| 515 | + dev_err(&pdev->dev, "wqebb_size must be power of 2\n"); |
|---|
| 520 | 516 | return -EINVAL; |
|---|
| 521 | 517 | } |
|---|
| 522 | 518 | |
|---|
| .. | .. |
|---|
| 530 | 526 | return -EINVAL; |
|---|
| 531 | 527 | } |
|---|
| 532 | 528 | |
|---|
| 533 | | - num_wqebbs_per_page = ALIGN(wq_page_size, wqebb_size) / wqebb_size; |
|---|
| 529 | + wqebb_size_shift = ilog2(wqebb_size); |
|---|
| 530 | + num_wqebbs_per_page = ALIGN(wq_page_size, wqebb_size) |
|---|
| 531 | + >> wqebb_size_shift; |
|---|
| 534 | 532 | |
|---|
| 535 | | - if (num_wqebbs_per_page & (num_wqebbs_per_page - 1)) { |
|---|
| 533 | + if (!is_power_of_2(num_wqebbs_per_page)) { |
|---|
| 536 | 534 | dev_err(&pdev->dev, "num wqebbs per page must be power of 2\n"); |
|---|
| 537 | 535 | return -EINVAL; |
|---|
| 538 | 536 | } |
|---|
| .. | .. |
|---|
| 550 | 548 | wq->q_depth = q_depth; |
|---|
| 551 | 549 | wq->max_wqe_size = max_wqe_size; |
|---|
| 552 | 550 | wq->num_wqebbs_per_page = num_wqebbs_per_page; |
|---|
| 553 | | - |
|---|
| 551 | + wq->wqebbs_per_page_shift = ilog2(num_wqebbs_per_page); |
|---|
| 552 | + wq->wqebb_size_shift = wqebb_size_shift; |
|---|
| 554 | 553 | wq->block_vaddr = WQ_BASE_VADDR(wqs, wq); |
|---|
| 555 | 554 | wq->shadow_block_vaddr = WQ_BASE_ADDR(wqs, wq); |
|---|
| 556 | 555 | wq->block_paddr = WQ_BASE_PADDR(wqs, wq); |
|---|
| .. | .. |
|---|
| 600 | 599 | **/ |
|---|
| 601 | 600 | int hinic_wqs_cmdq_alloc(struct hinic_cmdq_pages *cmdq_pages, |
|---|
| 602 | 601 | struct hinic_wq *wq, struct hinic_hwif *hwif, |
|---|
| 603 | | - int cmdq_blocks, u16 wqebb_size, u16 wq_page_size, |
|---|
| 602 | + int cmdq_blocks, u16 wqebb_size, u32 wq_page_size, |
|---|
| 604 | 603 | u16 q_depth, u16 max_wqe_size) |
|---|
| 605 | 604 | { |
|---|
| 606 | 605 | struct pci_dev *pdev = hwif->pdev; |
|---|
| 606 | + u16 num_wqebbs_per_page_shift; |
|---|
| 607 | 607 | u16 num_wqebbs_per_page; |
|---|
| 608 | + u16 wqebb_size_shift; |
|---|
| 608 | 609 | int i, j, err = -ENOMEM; |
|---|
| 609 | 610 | |
|---|
| 610 | | - if (wqebb_size == 0) { |
|---|
| 611 | | - dev_err(&pdev->dev, "wqebb_size must be > 0\n"); |
|---|
| 611 | + if (!is_power_of_2(wqebb_size)) { |
|---|
| 612 | + dev_err(&pdev->dev, "wqebb_size must be power of 2\n"); |
|---|
| 612 | 613 | return -EINVAL; |
|---|
| 613 | 614 | } |
|---|
| 614 | 615 | |
|---|
| .. | .. |
|---|
| 622 | 623 | return -EINVAL; |
|---|
| 623 | 624 | } |
|---|
| 624 | 625 | |
|---|
| 625 | | - num_wqebbs_per_page = ALIGN(wq_page_size, wqebb_size) / wqebb_size; |
|---|
| 626 | + wqebb_size_shift = ilog2(wqebb_size); |
|---|
| 627 | + num_wqebbs_per_page = ALIGN(wq_page_size, wqebb_size) |
|---|
| 628 | + >> wqebb_size_shift; |
|---|
| 626 | 629 | |
|---|
| 627 | | - if (num_wqebbs_per_page & (num_wqebbs_per_page - 1)) { |
|---|
| 630 | + if (!is_power_of_2(num_wqebbs_per_page)) { |
|---|
| 628 | 631 | dev_err(&pdev->dev, "num wqebbs per page must be power of 2\n"); |
|---|
| 629 | 632 | return -EINVAL; |
|---|
| 630 | 633 | } |
|---|
| .. | .. |
|---|
| 636 | 639 | dev_err(&pdev->dev, "Failed to allocate CMDQ page\n"); |
|---|
| 637 | 640 | return err; |
|---|
| 638 | 641 | } |
|---|
| 642 | + num_wqebbs_per_page_shift = ilog2(num_wqebbs_per_page); |
|---|
| 639 | 643 | |
|---|
| 640 | 644 | for (i = 0; i < cmdq_blocks; i++) { |
|---|
| 641 | 645 | wq[i].hwif = hwif; |
|---|
| .. | .. |
|---|
| 647 | 651 | wq[i].q_depth = q_depth; |
|---|
| 648 | 652 | wq[i].max_wqe_size = max_wqe_size; |
|---|
| 649 | 653 | wq[i].num_wqebbs_per_page = num_wqebbs_per_page; |
|---|
| 650 | | - |
|---|
| 654 | + wq[i].wqebbs_per_page_shift = num_wqebbs_per_page_shift; |
|---|
| 655 | + wq[i].wqebb_size_shift = wqebb_size_shift; |
|---|
| 651 | 656 | wq[i].block_vaddr = CMDQ_BASE_VADDR(cmdq_pages, &wq[i]); |
|---|
| 652 | 657 | wq[i].shadow_block_vaddr = CMDQ_BASE_ADDR(cmdq_pages, &wq[i]); |
|---|
| 653 | 658 | wq[i].block_paddr = CMDQ_BASE_PADDR(cmdq_pages, &wq[i]); |
|---|
| .. | .. |
|---|
| 741 | 746 | |
|---|
| 742 | 747 | *prod_idx = MASKED_WQE_IDX(wq, atomic_read(&wq->prod_idx)); |
|---|
| 743 | 748 | |
|---|
| 744 | | - num_wqebbs = ALIGN(wqe_size, wq->wqebb_size) / wq->wqebb_size; |
|---|
| 749 | + num_wqebbs = ALIGN(wqe_size, wq->wqebb_size) >> wq->wqebb_size_shift; |
|---|
| 745 | 750 | |
|---|
| 746 | 751 | if (atomic_sub_return(num_wqebbs, &wq->delta) <= 0) { |
|---|
| 747 | 752 | atomic_add(num_wqebbs, &wq->delta); |
|---|
| .. | .. |
|---|
| 762 | 767 | |
|---|
| 763 | 768 | *prod_idx = curr_prod_idx; |
|---|
| 764 | 769 | |
|---|
| 765 | | - if (curr_pg != end_pg) { |
|---|
| 770 | + /* If we only have one page, still need to get shadown wqe when |
|---|
| 771 | + * wqe rolling-over page |
|---|
| 772 | + */ |
|---|
| 773 | + if (curr_pg != end_pg || end_prod_idx < *prod_idx) { |
|---|
| 766 | 774 | void *shadow_addr = &wq->shadow_wqe[curr_pg * wq->max_wqe_size]; |
|---|
| 767 | 775 | |
|---|
| 768 | 776 | copy_wqe_to_shadow(wq, shadow_addr, num_wqebbs, *prod_idx); |
|---|
| .. | .. |
|---|
| 775 | 783 | } |
|---|
| 776 | 784 | |
|---|
| 777 | 785 | /** |
|---|
| 786 | + * hinic_return_wqe - return the wqe when transmit failed |
|---|
| 787 | + * @wq: wq to return wqe |
|---|
| 788 | + * @wqe_size: wqe size |
|---|
| 789 | + **/ |
|---|
| 790 | +void hinic_return_wqe(struct hinic_wq *wq, unsigned int wqe_size) |
|---|
| 791 | +{ |
|---|
| 792 | + int num_wqebbs = ALIGN(wqe_size, wq->wqebb_size) / wq->wqebb_size; |
|---|
| 793 | + |
|---|
| 794 | + atomic_sub(num_wqebbs, &wq->prod_idx); |
|---|
| 795 | + |
|---|
| 796 | + atomic_add(num_wqebbs, &wq->delta); |
|---|
| 797 | +} |
|---|
| 798 | + |
|---|
| 799 | +/** |
|---|
| 778 | 800 | * hinic_put_wqe - return the wqe place to use for a new wqe |
|---|
| 779 | 801 | * @wq: wq to return wqe |
|---|
| 780 | 802 | * @wqe_size: wqe size |
|---|
| 781 | 803 | **/ |
|---|
| 782 | 804 | void hinic_put_wqe(struct hinic_wq *wq, unsigned int wqe_size) |
|---|
| 783 | 805 | { |
|---|
| 784 | | - int num_wqebbs = ALIGN(wqe_size, wq->wqebb_size) / wq->wqebb_size; |
|---|
| 806 | + int num_wqebbs = ALIGN(wqe_size, wq->wqebb_size) |
|---|
| 807 | + >> wq->wqebb_size_shift; |
|---|
| 785 | 808 | |
|---|
| 786 | 809 | atomic_add(num_wqebbs, &wq->cons_idx); |
|---|
| 787 | 810 | |
|---|
| .. | .. |
|---|
| 799 | 822 | struct hinic_hw_wqe *hinic_read_wqe(struct hinic_wq *wq, unsigned int wqe_size, |
|---|
| 800 | 823 | u16 *cons_idx) |
|---|
| 801 | 824 | { |
|---|
| 802 | | - int num_wqebbs = ALIGN(wqe_size, wq->wqebb_size) / wq->wqebb_size; |
|---|
| 825 | + int num_wqebbs = ALIGN(wqe_size, wq->wqebb_size) |
|---|
| 826 | + >> wq->wqebb_size_shift; |
|---|
| 803 | 827 | u16 curr_cons_idx, end_cons_idx; |
|---|
| 804 | 828 | int curr_pg, end_pg; |
|---|
| 805 | 829 | |
|---|
| .. | .. |
|---|
| 816 | 840 | |
|---|
| 817 | 841 | *cons_idx = curr_cons_idx; |
|---|
| 818 | 842 | |
|---|
| 819 | | - if (curr_pg != end_pg) { |
|---|
| 843 | + /* If we only have one page, still need to get shadown wqe when |
|---|
| 844 | + * wqe rolling-over page |
|---|
| 845 | + */ |
|---|
| 846 | + if (curr_pg != end_pg || end_cons_idx < curr_cons_idx) { |
|---|
| 820 | 847 | void *shadow_addr = &wq->shadow_wqe[curr_pg * wq->max_wqe_size]; |
|---|
| 821 | 848 | |
|---|
| 822 | 849 | copy_wqe_to_shadow(wq, shadow_addr, num_wqebbs, *cons_idx); |
|---|