aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ntb
diff options
context:
space:
mode:
authorSerge Semin <fancer.lancer@gmail.com>2017-12-06 09:31:55 -0500
committerJon Mason <jdmason@kudzu.us>2018-01-28 22:17:24 -0500
commitc7aeb0afdcc2d1ec5945e164d3fb97c5ae3edd1a (patch)
treecbd5dd7df8516051d6b47ce25f16dd48a5ecc02e /drivers/ntb
parentf1678a4c66a5c2cb43f744f7dc7e048d59690166 (diff)
NTB: ntb_pp: Add full multi-port NTB API support
Current Ping Pong driver can't truly work with multi-port devices. Additionally it requires the Scratchpad registers being available on NTB device. This patches rewrites the driver so one would perform the cyclic Ping-Pong algorithm around all the available NTB peers and makes it working with NTB hardware, which doesn't support Scratchpads, but such alternative as NTB Message register. Additional cleanups are also added here. Signed-off-by: Serge Semin <fancer.lancer@gmail.com> Signed-off-by: Jon Mason <jdmason@kudzu.us>
Diffstat (limited to 'drivers/ntb')
-rw-r--r--drivers/ntb/test/ntb_pingpong.c447
1 files changed, 282 insertions, 165 deletions
diff --git a/drivers/ntb/test/ntb_pingpong.c b/drivers/ntb/test/ntb_pingpong.c
index e700873e03fb..65865e460ab8 100644
--- a/drivers/ntb/test/ntb_pingpong.c
+++ b/drivers/ntb/test/ntb_pingpong.c
@@ -1,10 +1,11 @@
1/* 1/*
2 * This file is provided under a dual BSD/GPLv2 license. When using or 2 * This file is provided under a dual BSD/GPLv2 license. When using or
3 * redistributing this file, you may do so under either license. 3 * redistributing this file, you may do so under either license.
4 * 4 *
5 * GPL LICENSE SUMMARY 5 * GPL LICENSE SUMMARY
6 * 6 *
7 * Copyright (C) 2015 EMC Corporation. All Rights Reserved. 7 * Copyright (C) 2015 EMC Corporation. All Rights Reserved.
8 * Copyright (C) 2017 T-Platforms. All Rights Reserved.
8 * 9 *
9 * This program is free software; you can redistribute it and/or modify 10 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of version 2 of the GNU General Public License as 11 * it under the terms of version 2 of the GNU General Public License as
@@ -18,6 +19,7 @@
18 * BSD LICENSE 19 * BSD LICENSE
19 * 20 *
20 * Copyright (C) 2015 EMC Corporation. All Rights Reserved. 21 * Copyright (C) 2015 EMC Corporation. All Rights Reserved.
22 * Copyright (C) 2017 T-Platforms. All Rights Reserved.
21 * 23 *
22 * Redistribution and use in source and binary forms, with or without 24 * Redistribution and use in source and binary forms, with or without
23 * modification, are permitted provided that the following conditions 25 * modification, are permitted provided that the following conditions
@@ -46,36 +48,45 @@
46 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 48 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47 * 49 *
48 * PCIe NTB Pingpong Linux driver 50 * PCIe NTB Pingpong Linux driver
49 *
50 * Contact Information:
51 * Allen Hubbe <Allen.Hubbe@emc.com>
52 */ 51 */
53 52
54/* Note: load this module with option 'dyndbg=+p' */ 53/*
54 * How to use this tool, by example.
55 *
56 * Assuming $DBG_DIR is something like:
57 * '/sys/kernel/debug/ntb_perf/0000:00:03.0'
58 * Suppose aside from local device there is at least one remote device
59 * connected to NTB with index 0.
60 *-----------------------------------------------------------------------------
61 * Eg: install driver with specified delay between doorbell event and response
62 *
63 * root@self# insmod ntb_pingpong.ko delay_ms=1000
64 *-----------------------------------------------------------------------------
65 * Eg: get number of ping-pong cycles performed
66 *
67 * root@self# cat $DBG_DIR/count
68 */
55 69
56#include <linux/init.h> 70#include <linux/init.h>
57#include <linux/kernel.h> 71#include <linux/kernel.h>
58#include <linux/module.h> 72#include <linux/module.h>
73#include <linux/device.h>
74#include <linux/bitops.h>
59 75
60#include <linux/dma-mapping.h>
61#include <linux/pci.h> 76#include <linux/pci.h>
62#include <linux/slab.h> 77#include <linux/slab.h>
63#include <linux/spinlock.h> 78#include <linux/hrtimer.h>
64#include <linux/debugfs.h> 79#include <linux/debugfs.h>
65 80
66#include <linux/ntb.h> 81#include <linux/ntb.h>
67 82
68#define DRIVER_NAME "ntb_pingpong" 83#define DRIVER_NAME "ntb_pingpong"
69#define DRIVER_DESCRIPTION "PCIe NTB Simple Pingpong Client" 84#define DRIVER_VERSION "2.0"
70
71#define DRIVER_VERSION "1.0"
72#define DRIVER_RELDATE "24 March 2015"
73#define DRIVER_AUTHOR "Allen Hubbe <Allen.Hubbe@emc.com>"
74 85
75MODULE_LICENSE("Dual BSD/GPL"); 86MODULE_LICENSE("Dual BSD/GPL");
76MODULE_VERSION(DRIVER_VERSION); 87MODULE_VERSION(DRIVER_VERSION);
77MODULE_AUTHOR(DRIVER_AUTHOR); 88MODULE_AUTHOR("Allen Hubbe <Allen.Hubbe@emc.com>");
78MODULE_DESCRIPTION(DRIVER_DESCRIPTION); 89MODULE_DESCRIPTION("PCIe NTB Simple Pingpong Client");
79 90
80static unsigned int unsafe; 91static unsigned int unsafe;
81module_param(unsafe, uint, 0644); 92module_param(unsafe, uint, 0644);
@@ -85,237 +96,343 @@ static unsigned int delay_ms = 1000;
85module_param(delay_ms, uint, 0644); 96module_param(delay_ms, uint, 0644);
86MODULE_PARM_DESC(delay_ms, "Milliseconds to delay the response to peer"); 97MODULE_PARM_DESC(delay_ms, "Milliseconds to delay the response to peer");
87 98
88static unsigned long db_init = 0x7;
89module_param(db_init, ulong, 0644);
90MODULE_PARM_DESC(db_init, "Initial doorbell bits to ring on the peer");
91
92/* Only two-ports NTB devices are supported */
93#define PIDX NTB_DEF_PEER_IDX
94
95struct pp_ctx { 99struct pp_ctx {
96 struct ntb_dev *ntb; 100 struct ntb_dev *ntb;
97 u64 db_bits; 101 struct hrtimer timer;
98 /* synchronize access to db_bits by ping and pong */ 102 u64 in_db;
99 spinlock_t db_lock; 103 u64 out_db;
100 struct timer_list db_timer; 104 int out_pidx;
101 unsigned long db_delay; 105 u64 nmask;
102 struct dentry *debugfs_node_dir; 106 u64 pmask;
103 struct dentry *debugfs_count; 107 atomic_t count;
104 atomic_t count; 108 spinlock_t lock;
109 struct dentry *dbgfs_dir;
105}; 110};
111#define to_pp_timer(__timer) \
112 container_of(__timer, struct pp_ctx, timer)
106 113
107static struct dentry *pp_debugfs_dir; 114static struct dentry *pp_dbgfs_topdir;
108 115
109static void pp_ping(struct timer_list *t) 116static int pp_find_next_peer(struct pp_ctx *pp)
110{ 117{
111 struct pp_ctx *pp = from_timer(pp, t, db_timer); 118 u64 link, out_db;
112 unsigned long irqflags; 119 int pidx;
113 u64 db_bits, db_mask; 120
114 u32 spad_rd, spad_wr; 121 link = ntb_link_is_up(pp->ntb, NULL, NULL);
122
123 /* Find next available peer */
124 if (link & pp->nmask) {
125 pidx = __ffs64(link & pp->nmask);
126 out_db = BIT_ULL(pidx + 1);
127 } else if (link & pp->pmask) {
128 pidx = __ffs64(link & pp->pmask);
129 out_db = BIT_ULL(pidx);
130 } else {
131 return -ENODEV;
132 }
115 133
116 spin_lock_irqsave(&pp->db_lock, irqflags); 134 spin_lock(&pp->lock);
117 { 135 pp->out_pidx = pidx;
118 db_mask = ntb_db_valid_mask(pp->ntb); 136 pp->out_db = out_db;
119 db_bits = ntb_db_read(pp->ntb); 137 spin_unlock(&pp->lock);
120 138
121 if (db_bits) { 139 return 0;
122 dev_dbg(&pp->ntb->dev, 140}
123 "Masked pongs %#llx\n",
124 db_bits);
125 ntb_db_clear(pp->ntb, db_bits);
126 }
127 141
128 db_bits = ((pp->db_bits | db_bits) << 1) & db_mask; 142static void pp_setup(struct pp_ctx *pp)
143{
144 int ret;
129 145
130 if (!db_bits) 146 ntb_db_set_mask(pp->ntb, pp->in_db);
131 db_bits = db_init;
132 147
133 spad_rd = ntb_spad_read(pp->ntb, 0); 148 hrtimer_cancel(&pp->timer);
134 spad_wr = spad_rd + 1;
135 149
136 dev_dbg(&pp->ntb->dev, 150 ret = pp_find_next_peer(pp);
137 "Ping bits %#llx read %#x write %#x\n", 151 if (ret == -ENODEV) {
138 db_bits, spad_rd, spad_wr); 152 dev_dbg(&pp->ntb->dev, "Got no peers, so cancel\n");
153 return;
154 }
139 155
140 ntb_peer_spad_write(pp->ntb, PIDX, 0, spad_wr); 156 dev_dbg(&pp->ntb->dev, "Ping-pong started with port %d, db %#llx\n",
141 ntb_peer_db_set(pp->ntb, db_bits); 157 ntb_peer_port_number(pp->ntb, pp->out_pidx), pp->out_db);
142 ntb_db_clear_mask(pp->ntb, db_mask);
143 158
144 pp->db_bits = 0; 159 hrtimer_start(&pp->timer, ms_to_ktime(delay_ms), HRTIMER_MODE_REL);
145 }
146 spin_unlock_irqrestore(&pp->db_lock, irqflags);
147} 160}
148 161
149static void pp_link_event(void *ctx) 162static void pp_clear(struct pp_ctx *pp)
150{ 163{
151 struct pp_ctx *pp = ctx; 164 hrtimer_cancel(&pp->timer);
152 165
153 if (ntb_link_is_up(pp->ntb, NULL, NULL) == 1) { 166 ntb_db_set_mask(pp->ntb, pp->in_db);
154 dev_dbg(&pp->ntb->dev, "link is up\n"); 167
155 pp_ping(&pp->db_timer); 168 dev_dbg(&pp->ntb->dev, "Ping-pong cancelled\n");
156 } else {
157 dev_dbg(&pp->ntb->dev, "link is down\n");
158 del_timer(&pp->db_timer);
159 }
160} 169}
161 170
162static void pp_db_event(void *ctx, int vec) 171static void pp_ping(struct pp_ctx *pp)
163{ 172{
164 struct pp_ctx *pp = ctx; 173 u32 count;
165 u64 db_bits, db_mask;
166 unsigned long irqflags;
167 174
168 spin_lock_irqsave(&pp->db_lock, irqflags); 175 count = atomic_read(&pp->count);
169 {
170 db_mask = ntb_db_vector_mask(pp->ntb, vec);
171 db_bits = db_mask & ntb_db_read(pp->ntb);
172 ntb_db_set_mask(pp->ntb, db_mask);
173 ntb_db_clear(pp->ntb, db_bits);
174 176
175 pp->db_bits |= db_bits; 177 spin_lock(&pp->lock);
178 ntb_peer_spad_write(pp->ntb, pp->out_pidx, 0, count);
179 ntb_peer_msg_write(pp->ntb, pp->out_pidx, 0, count);
176 180
177 mod_timer(&pp->db_timer, jiffies + pp->db_delay); 181 dev_dbg(&pp->ntb->dev, "Ping port %d spad %#x, msg %#x\n",
182 ntb_peer_port_number(pp->ntb, pp->out_pidx), count, count);
178 183
179 dev_dbg(&pp->ntb->dev, 184 ntb_peer_db_set(pp->ntb, pp->out_db);
180 "Pong vec %d bits %#llx\n", 185 ntb_db_clear_mask(pp->ntb, pp->in_db);
181 vec, db_bits); 186 spin_unlock(&pp->lock);
182 atomic_inc(&pp->count);
183 }
184 spin_unlock_irqrestore(&pp->db_lock, irqflags);
185} 187}
186 188
187static int pp_debugfs_setup(struct pp_ctx *pp) 189static void pp_pong(struct pp_ctx *pp)
188{ 190{
189 struct pci_dev *pdev = pp->ntb->pdev; 191 u32 msg_data = -1, spad_data = -1;
192 int pidx = 0;
190 193
191 if (!pp_debugfs_dir) 194 /* Read pong data */
192 return -ENODEV; 195 spad_data = ntb_spad_read(pp->ntb, 0);
196 msg_data = ntb_msg_read(pp->ntb, &pidx, 0);
197 ntb_msg_clear_sts(pp->ntb, -1);
193 198
194 pp->debugfs_node_dir = debugfs_create_dir(pci_name(pdev), 199 /*
195 pp_debugfs_dir); 200 * Scratchpad and message data may differ, since message register can't
196 if (!pp->debugfs_node_dir) 201 * be rewritten unless status is cleared. Additionally either of them
197 return -ENODEV; 202 * might be unsupported
203 */
204 dev_dbg(&pp->ntb->dev, "Pong spad %#x, msg %#x (port %d)\n",
205 spad_data, msg_data, ntb_peer_port_number(pp->ntb, pidx));
198 206
199 pp->debugfs_count = debugfs_create_atomic_t("count", S_IRUSR | S_IWUSR, 207 atomic_inc(&pp->count);
200 pp->debugfs_node_dir,
201 &pp->count);
202 if (!pp->debugfs_count)
203 return -ENODEV;
204 208
205 return 0; 209 ntb_db_set_mask(pp->ntb, pp->in_db);
210 ntb_db_clear(pp->ntb, pp->in_db);
211
212 hrtimer_start(&pp->timer, ms_to_ktime(delay_ms), HRTIMER_MODE_REL);
213}
214
215static enum hrtimer_restart pp_timer_func(struct hrtimer *t)
216{
217 struct pp_ctx *pp = to_pp_timer(t);
218
219 pp_ping(pp);
220
221 return HRTIMER_NORESTART;
222}
223
224static void pp_link_event(void *ctx)
225{
226 struct pp_ctx *pp = ctx;
227
228 pp_setup(pp);
229}
230
231static void pp_db_event(void *ctx, int vec)
232{
233 struct pp_ctx *pp = ctx;
234
235 pp_pong(pp);
206} 236}
207 237
208static const struct ntb_ctx_ops pp_ops = { 238static const struct ntb_ctx_ops pp_ops = {
209 .link_event = pp_link_event, 239 .link_event = pp_link_event,
210 .db_event = pp_db_event, 240 .db_event = pp_db_event
211}; 241};
212 242
213static int pp_probe(struct ntb_client *client, 243static int pp_check_ntb(struct ntb_dev *ntb)
214 struct ntb_dev *ntb)
215{ 244{
216 struct pp_ctx *pp; 245 u64 pmask;
217 int rc;
218 246
219 if (ntb_db_is_unsafe(ntb)) { 247 if (ntb_db_is_unsafe(ntb)) {
220 dev_dbg(&ntb->dev, "doorbell is unsafe\n"); 248 dev_dbg(&ntb->dev, "Doorbell is unsafe\n");
221 if (!unsafe) { 249 if (!unsafe)
222 rc = -EINVAL; 250 return -EINVAL;
223 goto err_pp;
224 }
225 }
226
227 if (ntb_spad_count(ntb) < 1) {
228 dev_dbg(&ntb->dev, "no enough scratchpads\n");
229 rc = -EINVAL;
230 goto err_pp;
231 } 251 }
232 252
233 if (ntb_spad_is_unsafe(ntb)) { 253 if (ntb_spad_is_unsafe(ntb)) {
234 dev_dbg(&ntb->dev, "scratchpad is unsafe\n"); 254 dev_dbg(&ntb->dev, "Scratchpad is unsafe\n");
235 if (!unsafe) { 255 if (!unsafe)
236 rc = -EINVAL; 256 return -EINVAL;
237 goto err_pp;
238 }
239 } 257 }
240 258
241 if (ntb_peer_port_count(ntb) != NTB_DEF_PEER_CNT) 259 pmask = GENMASK_ULL(ntb_peer_port_count(ntb), 0);
242 dev_warn(&ntb->dev, "multi-port NTB is unsupported\n"); 260 if ((ntb_db_valid_mask(ntb) & pmask) != pmask) {
261 dev_err(&ntb->dev, "Unsupported DB configuration\n");
262 return -EINVAL;
263 }
243 264
244 pp = kmalloc(sizeof(*pp), GFP_KERNEL); 265 if (ntb_spad_count(ntb) < 1 && ntb_msg_count(ntb) < 1) {
245 if (!pp) { 266 dev_err(&ntb->dev, "Scratchpads and messages unsupported\n");
246 rc = -ENOMEM; 267 return -EINVAL;
247 goto err_pp; 268 } else if (ntb_spad_count(ntb) < 1) {
269 dev_dbg(&ntb->dev, "Scratchpads unsupported\n");
270 } else if (ntb_msg_count(ntb) < 1) {
271 dev_dbg(&ntb->dev, "Messages unsupported\n");
248 } 272 }
249 273
274 return 0;
275}
276
277static struct pp_ctx *pp_create_data(struct ntb_dev *ntb)
278{
279 struct pp_ctx *pp;
280
281 pp = devm_kzalloc(&ntb->dev, sizeof(*pp), GFP_KERNEL);
282 if (!pp)
283 return ERR_PTR(-ENOMEM);
284
250 pp->ntb = ntb; 285 pp->ntb = ntb;
251 pp->db_bits = 0;
252 atomic_set(&pp->count, 0); 286 atomic_set(&pp->count, 0);
253 spin_lock_init(&pp->db_lock); 287 spin_lock_init(&pp->lock);
254 timer_setup(&pp->db_timer, pp_ping, 0); 288 hrtimer_init(&pp->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
255 pp->db_delay = msecs_to_jiffies(delay_ms); 289 pp->timer.function = pp_timer_func;
290
291 return pp;
292}
293
294static void pp_init_flds(struct pp_ctx *pp)
295{
296 int pidx, lport, pcnt;
297
298 /* Find global port index */
299 lport = ntb_port_number(pp->ntb);
300 pcnt = ntb_peer_port_count(pp->ntb);
301 for (pidx = 0; pidx < pcnt; pidx++) {
302 if (lport < ntb_peer_port_number(pp->ntb, pidx))
303 break;
304 }
256 305
257 rc = ntb_set_ctx(ntb, pp, &pp_ops); 306 pp->in_db = BIT_ULL(pidx);
258 if (rc) 307 pp->pmask = GENMASK_ULL(pidx, 0) >> 1;
259 goto err_ctx; 308 pp->nmask = GENMASK_ULL(pcnt - 1, pidx);
260 309
261 rc = pp_debugfs_setup(pp); 310 dev_dbg(&pp->ntb->dev, "Inbound db %#llx, prev %#llx, next %#llx\n",
262 if (rc) 311 pp->in_db, pp->pmask, pp->nmask);
263 goto err_ctx; 312}
313
314static int pp_mask_events(struct pp_ctx *pp)
315{
316 u64 db_mask, msg_mask;
317 int ret;
318
319 db_mask = ntb_db_valid_mask(pp->ntb);
320 ret = ntb_db_set_mask(pp->ntb, db_mask);
321 if (ret)
322 return ret;
264 323
265 ntb_link_enable(ntb, NTB_SPEED_AUTO, NTB_WIDTH_AUTO); 324 /* Skip message events masking if unsupported */
266 ntb_link_event(ntb); 325 if (ntb_msg_count(pp->ntb) < 1)
326 return 0;
327
328 msg_mask = ntb_msg_outbits(pp->ntb) | ntb_msg_inbits(pp->ntb);
329 return ntb_msg_set_mask(pp->ntb, msg_mask);
330}
331
332static int pp_setup_ctx(struct pp_ctx *pp)
333{
334 int ret;
335
336 ret = ntb_set_ctx(pp->ntb, pp, &pp_ops);
337 if (ret)
338 return ret;
339
340 ntb_link_enable(pp->ntb, NTB_SPEED_AUTO, NTB_WIDTH_AUTO);
341 /* Might be not necessary */
342 ntb_link_event(pp->ntb);
267 343
268 return 0; 344 return 0;
345}
346
347static void pp_clear_ctx(struct pp_ctx *pp)
348{
349 ntb_link_disable(pp->ntb);
269 350
270err_ctx: 351 ntb_clear_ctx(pp->ntb);
271 kfree(pp);
272err_pp:
273 return rc;
274} 352}
275 353
276static void pp_remove(struct ntb_client *client, 354static void pp_setup_dbgfs(struct pp_ctx *pp)
277 struct ntb_dev *ntb) 355{
356 struct pci_dev *pdev = pp->ntb->pdev;
357 void *ret;
358
359 pp->dbgfs_dir = debugfs_create_dir(pci_name(pdev), pp_dbgfs_topdir);
360
361 ret = debugfs_create_atomic_t("count", 0600, pp->dbgfs_dir, &pp->count);
362 if (!ret)
363 dev_warn(&pp->ntb->dev, "DebugFS unsupported\n");
364}
365
366static void pp_clear_dbgfs(struct pp_ctx *pp)
367{
368 debugfs_remove_recursive(pp->dbgfs_dir);
369}
370
371static int pp_probe(struct ntb_client *client, struct ntb_dev *ntb)
372{
373 struct pp_ctx *pp;
374 int ret;
375
376 ret = pp_check_ntb(ntb);
377 if (ret)
378 return ret;
379
380 pp = pp_create_data(ntb);
381 if (IS_ERR(pp))
382 return PTR_ERR(pp);
383
384 pp_init_flds(pp);
385
386 ret = pp_mask_events(pp);
387 if (ret)
388 return ret;
389
390 ret = pp_setup_ctx(pp);
391 if (ret)
392 return ret;
393
394 pp_setup_dbgfs(pp);
395
396 return 0;
397}
398
399static void pp_remove(struct ntb_client *client, struct ntb_dev *ntb)
278{ 400{
279 struct pp_ctx *pp = ntb->ctx; 401 struct pp_ctx *pp = ntb->ctx;
280 402
281 debugfs_remove_recursive(pp->debugfs_node_dir); 403 pp_clear_dbgfs(pp);
282 404
283 ntb_clear_ctx(ntb); 405 pp_clear_ctx(pp);
284 del_timer_sync(&pp->db_timer);
285 ntb_link_disable(ntb);
286 406
287 kfree(pp); 407 pp_clear(pp);
288} 408}
289 409
290static struct ntb_client pp_client = { 410static struct ntb_client pp_client = {
291 .ops = { 411 .ops = {
292 .probe = pp_probe, 412 .probe = pp_probe,
293 .remove = pp_remove, 413 .remove = pp_remove
294 }, 414 }
295}; 415};
296 416
297static int __init pp_init(void) 417static int __init pp_init(void)
298{ 418{
299 int rc; 419 int ret;
300 420
301 if (debugfs_initialized()) 421 if (debugfs_initialized())
302 pp_debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL); 422 pp_dbgfs_topdir = debugfs_create_dir(KBUILD_MODNAME, NULL);
303 423
304 rc = ntb_register_client(&pp_client); 424 ret = ntb_register_client(&pp_client);
305 if (rc) 425 if (ret)
306 goto err_client; 426 debugfs_remove_recursive(pp_dbgfs_topdir);
307 427
308 return 0; 428 return ret;
309
310err_client:
311 debugfs_remove_recursive(pp_debugfs_dir);
312 return rc;
313} 429}
314module_init(pp_init); 430module_init(pp_init);
315 431
316static void __exit pp_exit(void) 432static void __exit pp_exit(void)
317{ 433{
318 ntb_unregister_client(&pp_client); 434 ntb_unregister_client(&pp_client);
319 debugfs_remove_recursive(pp_debugfs_dir); 435 debugfs_remove_recursive(pp_dbgfs_topdir);
320} 436}
321module_exit(pp_exit); 437module_exit(pp_exit);
438