summaryrefslogtreecommitdiffstats
path: root/drivers/ntb/test
diff options
context:
space:
mode:
authorLogan Gunthorpe <logang@deltatee.com>2016-06-20 15:15:09 -0400
committerJon Mason <jdmason@kudzu.us>2016-08-05 10:21:07 -0400
commit717146a2a8cbf6dbcb8fdf4ae7cddd2d6074161c (patch)
tree46e4f9b227ba9a604b5ba298e29198cf6ce9ab77 /drivers/ntb/test
parent26dc638ae6e32bddfb8d3da0fc93946955c28c78 (diff)
ntb_tool: Postpone memory window initialization for the user
In order to make the interface closer to the raw NTB API, this commit changes memory windows so they are not initialized on link up. Instead, the 'peer_trans*' debugfs files are introduced. When read, they return information provided by ntb_mw_get_range. When written, they create a buffer and initialize the memory window. The value written is taken as the requested size of the buffer (which is then rounded for alignment). Writing a value of zero frees the buffer and tears down the memory window translation. The 'peer_mw*' file is only created once the memory window translation is setup by the user. Additionally, it was noticed that the read and write functions for the 'peer_mw*' files should have checked for a NULL pointer. Signed-off-by: Logan Gunthorpe <logang@deltatee.com> Acked-by: Allen Hubbe <Allen.Hubbe@emc.com> Signed-off-by: Jon Mason <jdmason@kudzu.us>
Diffstat (limited to 'drivers/ntb/test')
-rw-r--r--drivers/ntb/test/ntb_tool.c366
1 files changed, 228 insertions, 138 deletions
diff --git a/drivers/ntb/test/ntb_tool.c b/drivers/ntb/test/ntb_tool.c
index cba31fd0a07a..1509b4c1f204 100644
--- a/drivers/ntb/test/ntb_tool.c
+++ b/drivers/ntb/test/ntb_tool.c
@@ -79,6 +79,13 @@
79 * root@self# cat $DBG_DIR/spad 79 * root@self# cat $DBG_DIR/spad
80 * 80 *
81 * Observe that spad 0 and 1 have the values set by the peer. 81 * Observe that spad 0 and 1 have the values set by the peer.
82 *
83 * # Check the memory window translation info
84 * cat $DBG_DIR/peer_trans0
85 *
86 * # Setup a 16k memory window buffer
87 * echo 16384 > $DBG_DIR/peer_trans0
88 *
82 */ 89 */
83 90
84#include <linux/init.h> 91#include <linux/init.h>
@@ -108,25 +115,22 @@ MODULE_DESCRIPTION(DRIVER_DESCRIPTION);
108 115
109#define MAX_MWS 16 116#define MAX_MWS 16
110 117
111static unsigned long mw_size = 16;
112module_param(mw_size, ulong, 0644);
113MODULE_PARM_DESC(mw_size, "size order [n^2] of the memory window for testing");
114
115static struct dentry *tool_dbgfs; 118static struct dentry *tool_dbgfs;
116 119
117struct tool_mw { 120struct tool_mw {
121 int idx;
122 struct tool_ctx *tc;
123 resource_size_t win_size;
118 resource_size_t size; 124 resource_size_t size;
119 u8 __iomem *local; 125 u8 __iomem *local;
120 u8 *peer; 126 u8 *peer;
121 dma_addr_t peer_dma; 127 dma_addr_t peer_dma;
128 struct dentry *peer_dbg_file;
122}; 129};
123 130
124struct tool_ctx { 131struct tool_ctx {
125 struct ntb_dev *ntb; 132 struct ntb_dev *ntb;
126 struct dentry *dbgfs; 133 struct dentry *dbgfs;
127 struct work_struct link_cleanup;
128 bool link_is_up;
129 struct delayed_work link_work;
130 int mw_count; 134 int mw_count;
131 struct tool_mw mws[MAX_MWS]; 135 struct tool_mw mws[MAX_MWS];
132}; 136};
@@ -143,111 +147,6 @@ struct tool_ctx {
143 .write = __write, \ 147 .write = __write, \
144 } 148 }
145 149
146static int tool_setup_mw(struct tool_ctx *tc, int idx)
147{
148 int rc;
149 struct tool_mw *mw = &tc->mws[idx];
150 phys_addr_t base;
151 resource_size_t size, align, align_size;
152
153 if (mw->local)
154 return 0;
155
156 rc = ntb_mw_get_range(tc->ntb, idx, &base, &size, &align,
157 &align_size);
158 if (rc)
159 return rc;
160
161 mw->size = min_t(resource_size_t, 1 << mw_size, size);
162 mw->size = round_up(mw->size, align);
163 mw->size = round_up(mw->size, align_size);
164
165 mw->local = ioremap_wc(base, size);
166 if (mw->local == NULL)
167 return -EFAULT;
168
169 mw->peer = dma_alloc_coherent(&tc->ntb->pdev->dev, mw->size,
170 &mw->peer_dma, GFP_KERNEL);
171
172 if (mw->peer == NULL)
173 return -ENOMEM;
174
175 rc = ntb_mw_set_trans(tc->ntb, idx, mw->peer_dma, mw->size);
176 if (rc)
177 return rc;
178
179 return 0;
180}
181
182static void tool_free_mws(struct tool_ctx *tc)
183{
184 int i;
185
186 for (i = 0; i < tc->mw_count; i++) {
187 if (tc->mws[i].peer) {
188 ntb_mw_clear_trans(tc->ntb, i);
189 dma_free_coherent(&tc->ntb->pdev->dev, tc->mws[i].size,
190 tc->mws[i].peer,
191 tc->mws[i].peer_dma);
192
193 }
194
195 tc->mws[i].peer = NULL;
196 tc->mws[i].peer_dma = 0;
197
198 if (tc->mws[i].local)
199 iounmap(tc->mws[i].local);
200
201 tc->mws[i].local = NULL;
202 }
203
204 tc->mw_count = 0;
205}
206
207static int tool_setup_mws(struct tool_ctx *tc)
208{
209 int i;
210 int rc;
211
212 tc->mw_count = min(ntb_mw_count(tc->ntb), MAX_MWS);
213
214 for (i = 0; i < tc->mw_count; i++) {
215 rc = tool_setup_mw(tc, i);
216 if (rc)
217 goto err_out;
218 }
219
220 return 0;
221
222err_out:
223 tool_free_mws(tc);
224 return rc;
225}
226
227static void tool_link_work(struct work_struct *work)
228{
229 int rc;
230 struct tool_ctx *tc = container_of(work, struct tool_ctx,
231 link_work.work);
232
233 tool_free_mws(tc);
234 rc = tool_setup_mws(tc);
235 if (rc)
236 dev_err(&tc->ntb->dev,
237 "Error setting up memory windows: %d\n", rc);
238
239 tc->link_is_up = true;
240}
241
242static void tool_link_cleanup(struct work_struct *work)
243{
244 struct tool_ctx *tc = container_of(work, struct tool_ctx,
245 link_cleanup);
246
247 if (!tc->link_is_up)
248 cancel_delayed_work_sync(&tc->link_work);
249}
250
251static void tool_link_event(void *ctx) 150static void tool_link_event(void *ctx)
252{ 151{
253 struct tool_ctx *tc = ctx; 152 struct tool_ctx *tc = ctx;
@@ -260,10 +159,6 @@ static void tool_link_event(void *ctx)
260 dev_dbg(&tc->ntb->dev, "link is %s speed %d width %d\n", 159 dev_dbg(&tc->ntb->dev, "link is %s speed %d width %d\n",
261 up ? "up" : "down", speed, width); 160 up ? "up" : "down", speed, width);
262 161
263 if (up)
264 schedule_delayed_work(&tc->link_work, 2*HZ);
265 else
266 schedule_work(&tc->link_cleanup);
267} 162}
268 163
269static void tool_db_event(void *ctx, int vec) 164static void tool_db_event(void *ctx, int vec)
@@ -591,10 +486,10 @@ static ssize_t tool_mw_read(struct file *filep, char __user *ubuf,
591 return -EIO; 486 return -EIO;
592 if (pos < 0) 487 if (pos < 0)
593 return -EINVAL; 488 return -EINVAL;
594 if (pos >= mw->size || !size) 489 if (pos >= mw->win_size || !size)
595 return 0; 490 return 0;
596 if (size > mw->size - pos) 491 if (size > mw->win_size - pos)
597 size = mw->size - pos; 492 size = mw->win_size - pos;
598 493
599 buf = kmalloc(size, GFP_KERNEL); 494 buf = kmalloc(size, GFP_KERNEL);
600 if (!buf) 495 if (!buf)
@@ -627,10 +522,10 @@ static ssize_t tool_mw_write(struct file *filep, const char __user *ubuf,
627 522
628 if (pos < 0) 523 if (pos < 0)
629 return -EINVAL; 524 return -EINVAL;
630 if (pos >= mw->size || !size) 525 if (pos >= mw->win_size || !size)
631 return 0; 526 return 0;
632 if (size > mw->size - pos) 527 if (size > mw->win_size - pos)
633 size = mw->size - pos; 528 size = mw->win_size - pos;
634 529
635 buf = kmalloc(size, GFP_KERNEL); 530 buf = kmalloc(size, GFP_KERNEL);
636 if (!buf) 531 if (!buf)
@@ -658,20 +553,25 @@ static TOOL_FOPS_RDWR(tool_mw_fops,
658 tool_mw_read, 553 tool_mw_read,
659 tool_mw_write); 554 tool_mw_write);
660 555
661
662static ssize_t tool_peer_mw_read(struct file *filep, char __user *ubuf, 556static ssize_t tool_peer_mw_read(struct file *filep, char __user *ubuf,
663 size_t size, loff_t *offp) 557 size_t size, loff_t *offp)
664{ 558{
665 struct tool_mw *mw = filep->private_data; 559 struct tool_mw *mw = filep->private_data;
666 560
561 if (!mw->peer)
562 return -ENXIO;
563
667 return simple_read_from_buffer(ubuf, size, offp, mw->peer, mw->size); 564 return simple_read_from_buffer(ubuf, size, offp, mw->peer, mw->size);
668} 565}
669 566
670static ssize_t tool_peer_mw_write(struct file *filep, const char __user *ubuf, 567static ssize_t tool_peer_mw_write(struct file *filep, const char __user *ubuf,
671 size_t size, loff_t *offp) 568 size_t size, loff_t *offp)
672{ 569{
673 struct tool_mw *mw = filep->private_data; 570 struct tool_mw *mw = filep->private_data;
674 571
572 if (!mw->peer)
573 return -ENXIO;
574
675 return simple_write_to_buffer(mw->peer, mw->size, offp, ubuf, size); 575 return simple_write_to_buffer(mw->peer, mw->size, offp, ubuf, size);
676} 576}
677 577
@@ -679,9 +579,199 @@ static TOOL_FOPS_RDWR(tool_peer_mw_fops,
679 tool_peer_mw_read, 579 tool_peer_mw_read,
680 tool_peer_mw_write); 580 tool_peer_mw_write);
681 581
582static int tool_setup_mw(struct tool_ctx *tc, int idx, size_t req_size)
583{
584 int rc;
585 struct tool_mw *mw = &tc->mws[idx];
586 phys_addr_t base;
587 resource_size_t size, align, align_size;
588 char buf[16];
589
590 if (mw->peer)
591 return 0;
592
593 rc = ntb_mw_get_range(tc->ntb, idx, &base, &size, &align,
594 &align_size);
595 if (rc)
596 return rc;
597
598 mw->size = min_t(resource_size_t, req_size, size);
599 mw->size = round_up(mw->size, align);
600 mw->size = round_up(mw->size, align_size);
601 mw->peer = dma_alloc_coherent(&tc->ntb->pdev->dev, mw->size,
602 &mw->peer_dma, GFP_KERNEL);
603
604 if (!mw->peer)
605 return -ENOMEM;
606
607 rc = ntb_mw_set_trans(tc->ntb, idx, mw->peer_dma, mw->size);
608 if (rc)
609 goto err_free_dma;
610
611 snprintf(buf, sizeof(buf), "peer_mw%d", idx);
612 mw->peer_dbg_file = debugfs_create_file(buf, S_IRUSR | S_IWUSR,
613 mw->tc->dbgfs, mw,
614 &tool_peer_mw_fops);
615
616 return 0;
617
618err_free_dma:
619 dma_free_coherent(&tc->ntb->pdev->dev, mw->size,
620 mw->peer,
621 mw->peer_dma);
622 mw->peer = NULL;
623 mw->peer_dma = 0;
624 mw->size = 0;
625
626 return rc;
627}
628
629static void tool_free_mw(struct tool_ctx *tc, int idx)
630{
631 struct tool_mw *mw = &tc->mws[idx];
632
633 if (mw->peer) {
634 ntb_mw_clear_trans(tc->ntb, idx);
635 dma_free_coherent(&tc->ntb->pdev->dev, mw->size,
636 mw->peer,
637 mw->peer_dma);
638 }
639
640 mw->peer = NULL;
641 mw->peer_dma = 0;
642
643 debugfs_remove(mw->peer_dbg_file);
644
645 mw->peer_dbg_file = NULL;
646}
647
648static ssize_t tool_peer_mw_trans_read(struct file *filep,
649 char __user *ubuf,
650 size_t size, loff_t *offp)
651{
652 struct tool_mw *mw = filep->private_data;
653
654 char *buf;
655 size_t buf_size;
656 ssize_t ret, off = 0;
657
658 phys_addr_t base;
659 resource_size_t mw_size;
660 resource_size_t align;
661 resource_size_t align_size;
662
663 buf_size = min_t(size_t, size, 512);
664
665 buf = kmalloc(buf_size, GFP_KERNEL);
666 if (!buf)
667 return -ENOMEM;
668
669 ntb_mw_get_range(mw->tc->ntb, mw->idx,
670 &base, &mw_size, &align, &align_size);
671
672 off += scnprintf(buf + off, buf_size - off,
673 "Peer MW %d Information:\n", mw->idx);
674
675 off += scnprintf(buf + off, buf_size - off,
676 "Physical Address \t%pa[p]\n",
677 &base);
678
679 off += scnprintf(buf + off, buf_size - off,
680 "Window Size \t%lld\n",
681 (unsigned long long)mw_size);
682
683 off += scnprintf(buf + off, buf_size - off,
684 "Alignment \t%lld\n",
685 (unsigned long long)align);
686
687 off += scnprintf(buf + off, buf_size - off,
688 "Size Alignment \t%lld\n",
689 (unsigned long long)align_size);
690
691 off += scnprintf(buf + off, buf_size - off,
692 "Ready \t%c\n",
693 (mw->peer) ? 'Y' : 'N');
694
695 off += scnprintf(buf + off, buf_size - off,
696 "Allocated Size \t%zd\n",
697 (mw->peer) ? (size_t)mw->size : 0);
698
699 ret = simple_read_from_buffer(ubuf, size, offp, buf, off);
700 kfree(buf);
701 return ret;
702}
703
704static ssize_t tool_peer_mw_trans_write(struct file *filep,
705 const char __user *ubuf,
706 size_t size, loff_t *offp)
707{
708 struct tool_mw *mw = filep->private_data;
709
710 char buf[32];
711 size_t buf_size;
712 unsigned long long val;
713 int rc;
714
715 buf_size = min(size, (sizeof(buf) - 1));
716 if (copy_from_user(buf, ubuf, buf_size))
717 return -EFAULT;
718
719 buf[buf_size] = '\0';
720
721 rc = kstrtoull(buf, 0, &val);
722 if (rc)
723 return rc;
724
725 tool_free_mw(mw->tc, mw->idx);
726 if (val)
727 rc = tool_setup_mw(mw->tc, mw->idx, val);
728
729 if (rc)
730 return rc;
731
732 return size;
733}
734
735static TOOL_FOPS_RDWR(tool_peer_mw_trans_fops,
736 tool_peer_mw_trans_read,
737 tool_peer_mw_trans_write);
738
739static int tool_init_mw(struct tool_ctx *tc, int idx)
740{
741 struct tool_mw *mw = &tc->mws[idx];
742 phys_addr_t base;
743 int rc;
744
745 rc = ntb_mw_get_range(tc->ntb, idx, &base, &mw->win_size,
746 NULL, NULL);
747 if (rc)
748 return rc;
749
750 mw->tc = tc;
751 mw->idx = idx;
752 mw->local = ioremap_wc(base, mw->win_size);
753 if (!mw->local)
754 return -EFAULT;
755
756 return 0;
757}
758
759static void tool_free_mws(struct tool_ctx *tc)
760{
761 int i;
762
763 for (i = 0; i < tc->mw_count; i++) {
764 tool_free_mw(tc, i);
765
766 if (tc->mws[i].local)
767 iounmap(tc->mws[i].local);
768
769 tc->mws[i].local = NULL;
770 }
771}
772
682static void tool_setup_dbgfs(struct tool_ctx *tc) 773static void tool_setup_dbgfs(struct tool_ctx *tc)
683{ 774{
684 int mw_count;
685 int i; 775 int i;
686 776
687 /* This modules is useless without dbgfs... */ 777 /* This modules is useless without dbgfs... */
@@ -713,18 +803,16 @@ static void tool_setup_dbgfs(struct tool_ctx *tc)
713 debugfs_create_file("peer_spad", S_IRUSR | S_IWUSR, tc->dbgfs, 803 debugfs_create_file("peer_spad", S_IRUSR | S_IWUSR, tc->dbgfs,
714 tc, &tool_peer_spad_fops); 804 tc, &tool_peer_spad_fops);
715 805
716 mw_count = min(ntb_mw_count(tc->ntb), MAX_MWS); 806 for (i = 0; i < tc->mw_count; i++) {
717 for (i = 0; i < mw_count; i++) {
718 char buf[30]; 807 char buf[30];
719 808
720 snprintf(buf, sizeof(buf), "mw%d", i); 809 snprintf(buf, sizeof(buf), "mw%d", i);
721 debugfs_create_file(buf, S_IRUSR | S_IWUSR, tc->dbgfs, 810 debugfs_create_file(buf, S_IRUSR | S_IWUSR, tc->dbgfs,
722 &tc->mws[i], &tool_mw_fops); 811 &tc->mws[i], &tool_mw_fops);
723 812
724 snprintf(buf, sizeof(buf), "peer_mw%d", i); 813 snprintf(buf, sizeof(buf), "peer_trans%d", i);
725 debugfs_create_file(buf, S_IRUSR | S_IWUSR, tc->dbgfs, 814 debugfs_create_file(buf, S_IRUSR | S_IWUSR, tc->dbgfs,
726 &tc->mws[i], &tool_peer_mw_fops); 815 &tc->mws[i], &tool_peer_mw_trans_fops);
727
728 } 816 }
729} 817}
730 818
@@ -732,6 +820,7 @@ static int tool_probe(struct ntb_client *self, struct ntb_dev *ntb)
732{ 820{
733 struct tool_ctx *tc; 821 struct tool_ctx *tc;
734 int rc; 822 int rc;
823 int i;
735 824
736 if (ntb_db_is_unsafe(ntb)) 825 if (ntb_db_is_unsafe(ntb))
737 dev_dbg(&ntb->dev, "doorbell is unsafe\n"); 826 dev_dbg(&ntb->dev, "doorbell is unsafe\n");
@@ -746,8 +835,13 @@ static int tool_probe(struct ntb_client *self, struct ntb_dev *ntb)
746 } 835 }
747 836
748 tc->ntb = ntb; 837 tc->ntb = ntb;
749 INIT_DELAYED_WORK(&tc->link_work, tool_link_work); 838
750 INIT_WORK(&tc->link_cleanup, tool_link_cleanup); 839 tc->mw_count = min(ntb_mw_count(tc->ntb), MAX_MWS);
840 for (i = 0; i < tc->mw_count; i++) {
841 rc = tool_init_mw(tc, i);
842 if (rc)
843 goto err_ctx;
844 }
751 845
752 tool_setup_dbgfs(tc); 846 tool_setup_dbgfs(tc);
753 847
@@ -761,9 +855,8 @@ static int tool_probe(struct ntb_client *self, struct ntb_dev *ntb)
761 return 0; 855 return 0;
762 856
763err_ctx: 857err_ctx:
858 tool_free_mws(tc);
764 debugfs_remove_recursive(tc->dbgfs); 859 debugfs_remove_recursive(tc->dbgfs);
765 cancel_delayed_work_sync(&tc->link_work);
766 cancel_work_sync(&tc->link_cleanup);
767 kfree(tc); 860 kfree(tc);
768err_tc: 861err_tc:
769 return rc; 862 return rc;
@@ -773,9 +866,6 @@ static void tool_remove(struct ntb_client *self, struct ntb_dev *ntb)
773{ 866{
774 struct tool_ctx *tc = ntb->ctx; 867 struct tool_ctx *tc = ntb->ctx;
775 868
776 cancel_delayed_work_sync(&tc->link_work);
777 cancel_work_sync(&tc->link_cleanup);
778
779 tool_free_mws(tc); 869 tool_free_mws(tc);
780 870
781 ntb_clear_ctx(ntb); 871 ntb_clear_ctx(ntb);