.. | .. |
---|
| 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); |
---|