diff options
Diffstat (limited to 'drivers/scsi/cxgb3i')
-rw-r--r-- | drivers/scsi/cxgb3i/cxgb3i_ddp.c | 90 | ||||
-rw-r--r-- | drivers/scsi/cxgb3i/cxgb3i_ddp.h | 2 |
2 files changed, 71 insertions, 21 deletions
diff --git a/drivers/scsi/cxgb3i/cxgb3i_ddp.c b/drivers/scsi/cxgb3i/cxgb3i_ddp.c index 99c912547902..344fd53b9954 100644 --- a/drivers/scsi/cxgb3i/cxgb3i_ddp.c +++ b/drivers/scsi/cxgb3i/cxgb3i_ddp.c | |||
@@ -206,6 +206,31 @@ int cxgb3i_ddp_find_page_index(unsigned long pgsz) | |||
206 | return DDP_PGIDX_MAX; | 206 | return DDP_PGIDX_MAX; |
207 | } | 207 | } |
208 | 208 | ||
209 | /** | ||
210 | * cxgb3i_ddp_adjust_page_table - adjust page table with PAGE_SIZE | ||
211 | * return the ddp page index, if no match is found return DDP_PGIDX_MAX. | ||
212 | */ | ||
213 | int cxgb3i_ddp_adjust_page_table(void) | ||
214 | { | ||
215 | int i; | ||
216 | unsigned int base_order, order; | ||
217 | |||
218 | if (PAGE_SIZE < (1UL << ddp_page_shift[0])) { | ||
219 | ddp_log_info("PAGE_SIZE 0x%lx too small, min. 0x%lx.\n", | ||
220 | PAGE_SIZE, 1UL << ddp_page_shift[0]); | ||
221 | return -EINVAL; | ||
222 | } | ||
223 | |||
224 | base_order = get_order(1UL << ddp_page_shift[0]); | ||
225 | order = get_order(1 << PAGE_SHIFT); | ||
226 | for (i = 0; i < DDP_PGIDX_MAX; i++) { | ||
227 | /* first is the kernel page size, then just doubling the size */ | ||
228 | ddp_page_order[i] = order - base_order + i; | ||
229 | ddp_page_shift[i] = PAGE_SHIFT + i; | ||
230 | } | ||
231 | return 0; | ||
232 | } | ||
233 | |||
209 | static inline void ddp_gl_unmap(struct pci_dev *pdev, | 234 | static inline void ddp_gl_unmap(struct pci_dev *pdev, |
210 | struct cxgb3i_gather_list *gl) | 235 | struct cxgb3i_gather_list *gl) |
211 | { | 236 | { |
@@ -598,30 +623,40 @@ int cxgb3i_adapter_ddp_info(struct t3cdev *tdev, | |||
598 | * release all the resource held by the ddp pagepod manager for a given | 623 | * release all the resource held by the ddp pagepod manager for a given |
599 | * adapter if needed | 624 | * adapter if needed |
600 | */ | 625 | */ |
601 | void cxgb3i_ddp_cleanup(struct t3cdev *tdev) | 626 | |
627 | static void ddp_cleanup(struct kref *kref) | ||
602 | { | 628 | { |
629 | struct cxgb3i_ddp_info *ddp = container_of(kref, | ||
630 | struct cxgb3i_ddp_info, | ||
631 | refcnt); | ||
603 | int i = 0; | 632 | int i = 0; |
633 | |||
634 | ddp_log_info("kref release ddp 0x%p, t3dev 0x%p.\n", ddp, ddp->tdev); | ||
635 | |||
636 | ddp->tdev->ulp_iscsi = NULL; | ||
637 | while (i < ddp->nppods) { | ||
638 | struct cxgb3i_gather_list *gl = ddp->gl_map[i]; | ||
639 | if (gl) { | ||
640 | int npods = (gl->nelem + PPOD_PAGES_MAX - 1) | ||
641 | >> PPOD_PAGES_SHIFT; | ||
642 | ddp_log_info("t3dev 0x%p, ddp %d + %d.\n", | ||
643 | ddp->tdev, i, npods); | ||
644 | kfree(gl); | ||
645 | ddp_free_gl_skb(ddp, i, npods); | ||
646 | i += npods; | ||
647 | } else | ||
648 | i++; | ||
649 | } | ||
650 | cxgb3i_free_big_mem(ddp); | ||
651 | } | ||
652 | |||
653 | void cxgb3i_ddp_cleanup(struct t3cdev *tdev) | ||
654 | { | ||
604 | struct cxgb3i_ddp_info *ddp = (struct cxgb3i_ddp_info *)tdev->ulp_iscsi; | 655 | struct cxgb3i_ddp_info *ddp = (struct cxgb3i_ddp_info *)tdev->ulp_iscsi; |
605 | 656 | ||
606 | ddp_log_info("t3dev 0x%p, release ddp 0x%p.\n", tdev, ddp); | 657 | ddp_log_info("t3dev 0x%p, release ddp 0x%p.\n", tdev, ddp); |
607 | 658 | if (ddp) | |
608 | if (ddp) { | 659 | kref_put(&ddp->refcnt, ddp_cleanup); |
609 | tdev->ulp_iscsi = NULL; | ||
610 | while (i < ddp->nppods) { | ||
611 | struct cxgb3i_gather_list *gl = ddp->gl_map[i]; | ||
612 | if (gl) { | ||
613 | int npods = (gl->nelem + PPOD_PAGES_MAX - 1) | ||
614 | >> PPOD_PAGES_SHIFT; | ||
615 | ddp_log_info("t3dev 0x%p, ddp %d + %d.\n", | ||
616 | tdev, i, npods); | ||
617 | kfree(gl); | ||
618 | ddp_free_gl_skb(ddp, i, npods); | ||
619 | i += npods; | ||
620 | } else | ||
621 | i++; | ||
622 | } | ||
623 | cxgb3i_free_big_mem(ddp); | ||
624 | } | ||
625 | } | 660 | } |
626 | 661 | ||
627 | /** | 662 | /** |
@@ -631,12 +666,13 @@ void cxgb3i_ddp_cleanup(struct t3cdev *tdev) | |||
631 | */ | 666 | */ |
632 | static void ddp_init(struct t3cdev *tdev) | 667 | static void ddp_init(struct t3cdev *tdev) |
633 | { | 668 | { |
634 | struct cxgb3i_ddp_info *ddp; | 669 | struct cxgb3i_ddp_info *ddp = tdev->ulp_iscsi; |
635 | struct ulp_iscsi_info uinfo; | 670 | struct ulp_iscsi_info uinfo; |
636 | unsigned int ppmax, bits; | 671 | unsigned int ppmax, bits; |
637 | int i, err; | 672 | int i, err; |
638 | 673 | ||
639 | if (tdev->ulp_iscsi) { | 674 | if (ddp) { |
675 | kref_get(&ddp->refcnt); | ||
640 | ddp_log_warn("t3dev 0x%p, ddp 0x%p already set up.\n", | 676 | ddp_log_warn("t3dev 0x%p, ddp 0x%p already set up.\n", |
641 | tdev, tdev->ulp_iscsi); | 677 | tdev, tdev->ulp_iscsi); |
642 | return; | 678 | return; |
@@ -670,6 +706,7 @@ static void ddp_init(struct t3cdev *tdev) | |||
670 | ppmax * | 706 | ppmax * |
671 | sizeof(struct cxgb3i_gather_list *)); | 707 | sizeof(struct cxgb3i_gather_list *)); |
672 | spin_lock_init(&ddp->map_lock); | 708 | spin_lock_init(&ddp->map_lock); |
709 | kref_init(&ddp->refcnt); | ||
673 | 710 | ||
674 | ddp->tdev = tdev; | 711 | ddp->tdev = tdev; |
675 | ddp->pdev = uinfo.pdev; | 712 | ddp->pdev = uinfo.pdev; |
@@ -715,6 +752,17 @@ void cxgb3i_ddp_init(struct t3cdev *tdev) | |||
715 | { | 752 | { |
716 | if (page_idx == DDP_PGIDX_MAX) { | 753 | if (page_idx == DDP_PGIDX_MAX) { |
717 | page_idx = cxgb3i_ddp_find_page_index(PAGE_SIZE); | 754 | page_idx = cxgb3i_ddp_find_page_index(PAGE_SIZE); |
755 | |||
756 | if (page_idx == DDP_PGIDX_MAX) { | ||
757 | ddp_log_info("system PAGE_SIZE %lu, update hw.\n", | ||
758 | PAGE_SIZE); | ||
759 | if (cxgb3i_ddp_adjust_page_table() < 0) { | ||
760 | ddp_log_info("PAGE_SIZE %lu, ddp disabled.\n", | ||
761 | PAGE_SIZE); | ||
762 | return; | ||
763 | } | ||
764 | page_idx = cxgb3i_ddp_find_page_index(PAGE_SIZE); | ||
765 | } | ||
718 | ddp_log_info("system PAGE_SIZE %lu, ddp idx %u.\n", | 766 | ddp_log_info("system PAGE_SIZE %lu, ddp idx %u.\n", |
719 | PAGE_SIZE, page_idx); | 767 | PAGE_SIZE, page_idx); |
720 | } | 768 | } |
diff --git a/drivers/scsi/cxgb3i/cxgb3i_ddp.h b/drivers/scsi/cxgb3i/cxgb3i_ddp.h index 0d296de7cf32..87dd56b422bf 100644 --- a/drivers/scsi/cxgb3i/cxgb3i_ddp.h +++ b/drivers/scsi/cxgb3i/cxgb3i_ddp.h | |||
@@ -54,6 +54,7 @@ struct cxgb3i_gather_list { | |||
54 | * struct cxgb3i_ddp_info - cxgb3i direct data placement for pdu payload | 54 | * struct cxgb3i_ddp_info - cxgb3i direct data placement for pdu payload |
55 | * | 55 | * |
56 | * @list: list head to link elements | 56 | * @list: list head to link elements |
57 | * @refcnt: ref. count | ||
57 | * @tdev: pointer to t3cdev used by cxgb3 driver | 58 | * @tdev: pointer to t3cdev used by cxgb3 driver |
58 | * @max_txsz: max tx packet size for ddp | 59 | * @max_txsz: max tx packet size for ddp |
59 | * @max_rxsz: max rx packet size for ddp | 60 | * @max_rxsz: max rx packet size for ddp |
@@ -70,6 +71,7 @@ struct cxgb3i_gather_list { | |||
70 | */ | 71 | */ |
71 | struct cxgb3i_ddp_info { | 72 | struct cxgb3i_ddp_info { |
72 | struct list_head list; | 73 | struct list_head list; |
74 | struct kref refcnt; | ||
73 | struct t3cdev *tdev; | 75 | struct t3cdev *tdev; |
74 | struct pci_dev *pdev; | 76 | struct pci_dev *pdev; |
75 | unsigned int max_txsz; | 77 | unsigned int max_txsz; |