1 // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
3 #include <linux/module.h>
4 #include <linux/debugfs.h>
7 #include <linux/radix-tree.h>
8 #include <linux/workqueue.h>
10 MODULE_LICENSE("Dual BSD/GPL");
11 MODULE_VERSION("0.1");
12 MODULE_AUTHOR("Logan Gunthorpe <logang@deltatee.com>");
13 MODULE_DESCRIPTION("Test for sending MSI interrupts over an NTB memory window");
15 static int num_irqs
= 4;
16 module_param(num_irqs
, int, 0644);
17 MODULE_PARM_DESC(num_irqs
, "number of irqs to use");
21 struct dentry
*dbgfs_dir
;
22 struct work_struct setup_work
;
24 struct ntb_msit_isr_ctx
{
28 struct ntb_msit_ctx
*nm
;
29 struct ntb_msi_desc desc
;
32 struct ntb_msit_peer
{
33 struct ntb_msit_ctx
*nm
;
36 struct completion init_comp
;
37 struct ntb_msi_desc
*msi_desc
;
41 static struct dentry
*ntb_msit_dbgfs_topdir
;
43 static irqreturn_t
ntb_msit_isr(int irq
, void *dev
)
45 struct ntb_msit_isr_ctx
*isr_ctx
= dev
;
46 struct ntb_msit_ctx
*nm
= isr_ctx
->nm
;
48 dev_dbg(&nm
->ntb
->dev
, "Interrupt Occurred: %d",
51 isr_ctx
->occurrences
++;
56 static void ntb_msit_setup_work(struct work_struct
*work
)
58 struct ntb_msit_ctx
*nm
= container_of(work
, struct ntb_msit_ctx
,
65 ret
= ntb_msi_setup_mws(nm
->ntb
);
67 dev_err(&nm
->ntb
->dev
, "Unable to setup MSI windows: %d\n",
72 for (i
= 0; i
< num_irqs
; i
++) {
73 nm
->isr_ctx
[i
].irq_idx
= i
;
74 nm
->isr_ctx
[i
].nm
= nm
;
76 if (!nm
->isr_ctx
[i
].irq_num
) {
77 irq
= ntbm_msi_request_irq(nm
->ntb
, ntb_msit_isr
,
80 &nm
->isr_ctx
[i
].desc
);
84 nm
->isr_ctx
[i
].irq_num
= irq
;
87 ret
= ntb_spad_write(nm
->ntb
, 2 * i
+ 1,
88 nm
->isr_ctx
[i
].desc
.addr_offset
);
92 ret
= ntb_spad_write(nm
->ntb
, 2 * i
+ 2,
93 nm
->isr_ctx
[i
].desc
.data
);
100 ntb_spad_write(nm
->ntb
, 0, irq_count
);
101 ntb_peer_db_set(nm
->ntb
, BIT(ntb_port_number(nm
->ntb
)));
104 static void ntb_msit_desc_changed(void *ctx
)
106 struct ntb_msit_ctx
*nm
= ctx
;
109 dev_dbg(&nm
->ntb
->dev
, "MSI Descriptors Changed\n");
111 for (i
= 0; i
< num_irqs
; i
++) {
112 ntb_spad_write(nm
->ntb
, 2 * i
+ 1,
113 nm
->isr_ctx
[i
].desc
.addr_offset
);
114 ntb_spad_write(nm
->ntb
, 2 * i
+ 2,
115 nm
->isr_ctx
[i
].desc
.data
);
118 ntb_peer_db_set(nm
->ntb
, BIT(ntb_port_number(nm
->ntb
)));
121 static void ntb_msit_link_event(void *ctx
)
123 struct ntb_msit_ctx
*nm
= ctx
;
125 if (!ntb_link_is_up(nm
->ntb
, NULL
, NULL
))
128 schedule_work(&nm
->setup_work
);
131 static void ntb_msit_copy_peer_desc(struct ntb_msit_ctx
*nm
, int peer
)
134 struct ntb_msi_desc
*desc
= nm
->peers
[peer
].msi_desc
;
135 int irq_count
= nm
->peers
[peer
].num_irqs
;
137 for (i
= 0; i
< irq_count
; i
++) {
138 desc
[i
].addr_offset
= ntb_peer_spad_read(nm
->ntb
, peer
,
140 desc
[i
].data
= ntb_peer_spad_read(nm
->ntb
, peer
, 2 * i
+ 2);
143 dev_info(&nm
->ntb
->dev
, "Found %d interrupts on peer %d\n",
146 complete_all(&nm
->peers
[peer
].init_comp
);
149 static void ntb_msit_db_event(void *ctx
, int vec
)
151 struct ntb_msit_ctx
*nm
= ctx
;
152 struct ntb_msi_desc
*desc
;
153 u64 peer_mask
= ntb_db_read(nm
->ntb
);
157 ntb_db_clear(nm
->ntb
, peer_mask
);
159 for (peer
= 0; peer
< sizeof(peer_mask
) * 8; peer
++) {
160 if (!(peer_mask
& BIT(peer
)))
163 irq_count
= ntb_peer_spad_read(nm
->ntb
, peer
, 0);
167 desc
= kcalloc(irq_count
, sizeof(*desc
), GFP_ATOMIC
);
171 kfree(nm
->peers
[peer
].msi_desc
);
172 nm
->peers
[peer
].msi_desc
= desc
;
173 nm
->peers
[peer
].num_irqs
= irq_count
;
175 ntb_msit_copy_peer_desc(nm
, peer
);
179 static const struct ntb_ctx_ops ntb_msit_ops
= {
180 .link_event
= ntb_msit_link_event
,
181 .db_event
= ntb_msit_db_event
,
184 static int ntb_msit_dbgfs_trigger(void *data
, u64 idx
)
186 struct ntb_msit_peer
*peer
= data
;
188 if (idx
>= peer
->num_irqs
)
191 dev_dbg(&peer
->nm
->ntb
->dev
, "trigger irq %llu on peer %u\n",
194 return ntb_msi_peer_trigger(peer
->nm
->ntb
, peer
->pidx
,
195 &peer
->msi_desc
[idx
]);
198 DEFINE_DEBUGFS_ATTRIBUTE(ntb_msit_trigger_fops
, NULL
,
199 ntb_msit_dbgfs_trigger
, "%llu\n");
201 static int ntb_msit_dbgfs_port_get(void *data
, u64
*port
)
203 struct ntb_msit_peer
*peer
= data
;
205 *port
= ntb_peer_port_number(peer
->nm
->ntb
, peer
->pidx
);
210 DEFINE_DEBUGFS_ATTRIBUTE(ntb_msit_port_fops
, ntb_msit_dbgfs_port_get
,
213 static int ntb_msit_dbgfs_count_get(void *data
, u64
*count
)
215 struct ntb_msit_peer
*peer
= data
;
217 *count
= peer
->num_irqs
;
222 DEFINE_DEBUGFS_ATTRIBUTE(ntb_msit_count_fops
, ntb_msit_dbgfs_count_get
,
225 static int ntb_msit_dbgfs_ready_get(void *data
, u64
*ready
)
227 struct ntb_msit_peer
*peer
= data
;
229 *ready
= try_wait_for_completion(&peer
->init_comp
);
234 static int ntb_msit_dbgfs_ready_set(void *data
, u64 ready
)
236 struct ntb_msit_peer
*peer
= data
;
238 return wait_for_completion_interruptible(&peer
->init_comp
);
241 DEFINE_DEBUGFS_ATTRIBUTE(ntb_msit_ready_fops
, ntb_msit_dbgfs_ready_get
,
242 ntb_msit_dbgfs_ready_set
, "%llu\n");
244 static int ntb_msit_dbgfs_occurrences_get(void *data
, u64
*occurrences
)
246 struct ntb_msit_isr_ctx
*isr_ctx
= data
;
248 *occurrences
= isr_ctx
->occurrences
;
253 DEFINE_DEBUGFS_ATTRIBUTE(ntb_msit_occurrences_fops
,
254 ntb_msit_dbgfs_occurrences_get
,
257 static int ntb_msit_dbgfs_local_port_get(void *data
, u64
*port
)
259 struct ntb_msit_ctx
*nm
= data
;
261 *port
= ntb_port_number(nm
->ntb
);
266 DEFINE_DEBUGFS_ATTRIBUTE(ntb_msit_local_port_fops
,
267 ntb_msit_dbgfs_local_port_get
,
270 static void ntb_msit_create_dbgfs(struct ntb_msit_ctx
*nm
)
272 struct pci_dev
*pdev
= nm
->ntb
->pdev
;
275 struct dentry
*peer_dir
;
277 nm
->dbgfs_dir
= debugfs_create_dir(pci_name(pdev
),
278 ntb_msit_dbgfs_topdir
);
279 debugfs_create_file("port", 0400, nm
->dbgfs_dir
, nm
,
280 &ntb_msit_local_port_fops
);
282 for (i
= 0; i
< ntb_peer_port_count(nm
->ntb
); i
++) {
283 nm
->peers
[i
].pidx
= i
;
284 nm
->peers
[i
].nm
= nm
;
285 init_completion(&nm
->peers
[i
].init_comp
);
287 snprintf(buf
, sizeof(buf
), "peer%d", i
);
288 peer_dir
= debugfs_create_dir(buf
, nm
->dbgfs_dir
);
290 debugfs_create_file_unsafe("trigger", 0200, peer_dir
,
292 &ntb_msit_trigger_fops
);
294 debugfs_create_file_unsafe("port", 0400, peer_dir
,
295 &nm
->peers
[i
], &ntb_msit_port_fops
);
297 debugfs_create_file_unsafe("count", 0400, peer_dir
,
299 &ntb_msit_count_fops
);
301 debugfs_create_file_unsafe("ready", 0600, peer_dir
,
303 &ntb_msit_ready_fops
);
306 for (i
= 0; i
< num_irqs
; i
++) {
307 snprintf(buf
, sizeof(buf
), "irq%d_occurrences", i
);
308 debugfs_create_file_unsafe(buf
, 0400, nm
->dbgfs_dir
,
310 &ntb_msit_occurrences_fops
);
314 static void ntb_msit_remove_dbgfs(struct ntb_msit_ctx
*nm
)
316 debugfs_remove_recursive(nm
->dbgfs_dir
);
319 static int ntb_msit_probe(struct ntb_client
*client
, struct ntb_dev
*ntb
)
321 struct ntb_msit_ctx
*nm
;
325 peers
= ntb_peer_port_count(ntb
);
329 if (ntb_spad_is_unsafe(ntb
) || ntb_spad_count(ntb
) < 2 * num_irqs
+ 1) {
330 dev_err(&ntb
->dev
, "NTB MSI test requires at least %d spads for %d irqs\n",
331 2 * num_irqs
+ 1, num_irqs
);
335 ret
= ntb_spad_write(ntb
, 0, -1);
337 dev_err(&ntb
->dev
, "Unable to write spads: %d\n", ret
);
341 ret
= ntb_db_clear_mask(ntb
, GENMASK(peers
- 1, 0));
343 dev_err(&ntb
->dev
, "Unable to clear doorbell mask: %d\n", ret
);
347 ret
= ntb_msi_init(ntb
, ntb_msit_desc_changed
);
349 dev_err(&ntb
->dev
, "Unable to initialize MSI library: %d\n",
354 nm
= devm_kzalloc(&ntb
->dev
, struct_size(nm
, peers
, peers
), GFP_KERNEL
);
358 nm
->isr_ctx
= devm_kcalloc(&ntb
->dev
, num_irqs
, sizeof(*nm
->isr_ctx
),
363 INIT_WORK(&nm
->setup_work
, ntb_msit_setup_work
);
366 ntb_msit_create_dbgfs(nm
);
368 ret
= ntb_set_ctx(ntb
, nm
, &ntb_msit_ops
);
375 ntb_link_enable(ntb
, NTB_SPEED_AUTO
, NTB_WIDTH_AUTO
);
380 ntb_msit_remove_dbgfs(nm
);
381 devm_kfree(&ntb
->dev
, nm
->isr_ctx
);
382 devm_kfree(&ntb
->dev
, nm
);
386 static void ntb_msit_remove(struct ntb_client
*client
, struct ntb_dev
*ntb
)
388 struct ntb_msit_ctx
*nm
= ntb
->ctx
;
391 ntb_link_disable(ntb
);
392 ntb_db_set_mask(ntb
, ntb_db_valid_mask(ntb
));
393 ntb_msi_clear_mws(ntb
);
395 for (i
= 0; i
< ntb_peer_port_count(ntb
); i
++)
396 kfree(nm
->peers
[i
].msi_desc
);
399 ntb_msit_remove_dbgfs(nm
);
402 static struct ntb_client ntb_msit_client
= {
404 .probe
= ntb_msit_probe
,
405 .remove
= ntb_msit_remove
409 static int __init
ntb_msit_init(void)
413 if (debugfs_initialized())
414 ntb_msit_dbgfs_topdir
= debugfs_create_dir(KBUILD_MODNAME
,
417 ret
= ntb_register_client(&ntb_msit_client
);
419 debugfs_remove_recursive(ntb_msit_dbgfs_topdir
);
423 module_init(ntb_msit_init
);
425 static void __exit
ntb_msit_exit(void)
427 ntb_unregister_client(&ntb_msit_client
);
428 debugfs_remove_recursive(ntb_msit_dbgfs_topdir
);
430 module_exit(ntb_msit_exit
);