aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Vrabel <david.vrabel@csr.com>2008-11-26 08:36:59 -0500
committerDavid Vrabel <david.vrabel@csr.com>2008-11-26 08:36:59 -0500
commitdcc7461eef7341e84e2f7274f904ce01a43b2506 (patch)
tree25afd640b7ed7fc1efc29fd0075f0d399af93e84
parente4b49580f70380a4216ff8220c8f48a95e21c238 (diff)
wusb: add debug files for ASL, PZL and DI to the whci-hcd driver
Add asl, pzl and di debugfs files to uwb/uwbN/wusbhc for WHCI host controller. These dump the current ASL, PZL and DI buffer. Signed-off-by: David Vrabel <david.vrabel@csr.com>
-rw-r--r--drivers/usb/host/whci/Kbuild1
-rw-r--r--drivers/usb/host/whci/asl.c25
-rw-r--r--drivers/usb/host/whci/debug.c189
-rw-r--r--drivers/usb/host/whci/hcd.c3
-rw-r--r--drivers/usb/host/whci/pzl.c28
-rw-r--r--drivers/usb/host/whci/qset.c40
-rw-r--r--drivers/usb/host/whci/whcd.h9
-rw-r--r--drivers/usb/host/whci/wusb.c27
-rw-r--r--drivers/uwb/pal.c5
-rw-r--r--drivers/uwb/uwb-debug.c13
-rw-r--r--drivers/uwb/uwb-internal.h3
-rw-r--r--include/linux/uwb.h3
12 files changed, 223 insertions, 123 deletions
diff --git a/drivers/usb/host/whci/Kbuild b/drivers/usb/host/whci/Kbuild
index 26a3871ea0f9..11e5040b8337 100644
--- a/drivers/usb/host/whci/Kbuild
+++ b/drivers/usb/host/whci/Kbuild
@@ -2,6 +2,7 @@ obj-$(CONFIG_USB_WHCI_HCD) += whci-hcd.o
2 2
3whci-hcd-y := \ 3whci-hcd-y := \
4 asl.o \ 4 asl.o \
5 debug.o \
5 hcd.o \ 6 hcd.o \
6 hw.o \ 7 hw.o \
7 init.o \ 8 init.o \
diff --git a/drivers/usb/host/whci/asl.c b/drivers/usb/host/whci/asl.c
index ba99a7a3f81a..577c0d29849d 100644
--- a/drivers/usb/host/whci/asl.c
+++ b/drivers/usb/host/whci/asl.c
@@ -19,32 +19,11 @@
19#include <linux/dma-mapping.h> 19#include <linux/dma-mapping.h>
20#include <linux/uwb/umc.h> 20#include <linux/uwb/umc.h>
21#include <linux/usb.h> 21#include <linux/usb.h>
22#define D_LOCAL 0
23#include <linux/uwb/debug.h>
24 22
25#include "../../wusbcore/wusbhc.h" 23#include "../../wusbcore/wusbhc.h"
26 24
27#include "whcd.h" 25#include "whcd.h"
28 26
29#if D_LOCAL >= 4
30static void dump_asl(struct whc *whc, const char *tag)
31{
32 struct device *dev = &whc->umc->dev;
33 struct whc_qset *qset;
34
35 d_printf(4, dev, "ASL %s\n", tag);
36
37 list_for_each_entry(qset, &whc->async_list, list_node) {
38 dump_qset(qset, dev);
39 }
40}
41#else
42static inline void dump_asl(struct whc *whc, const char *tag)
43{
44}
45#endif
46
47
48static void qset_get_next_prev(struct whc *whc, struct whc_qset *qset, 27static void qset_get_next_prev(struct whc *whc, struct whc_qset *qset,
49 struct whc_qset **next, struct whc_qset **prev) 28 struct whc_qset **next, struct whc_qset **prev)
50{ 29{
@@ -217,8 +196,6 @@ void scan_async_work(struct work_struct *work)
217 196
218 spin_lock_irq(&whc->lock); 197 spin_lock_irq(&whc->lock);
219 198
220 dump_asl(whc, "before processing");
221
222 /* 199 /*
223 * Transerve the software list backwards so new qsets can be 200 * Transerve the software list backwards so new qsets can be
224 * safely inserted into the ASL without making it non-circular. 201 * safely inserted into the ASL without making it non-circular.
@@ -232,8 +209,6 @@ void scan_async_work(struct work_struct *work)
232 update |= process_qset(whc, qset); 209 update |= process_qset(whc, qset);
233 } 210 }
234 211
235 dump_asl(whc, "after processing");
236
237 spin_unlock_irq(&whc->lock); 212 spin_unlock_irq(&whc->lock);
238 213
239 if (update) { 214 if (update) {
diff --git a/drivers/usb/host/whci/debug.c b/drivers/usb/host/whci/debug.c
new file mode 100644
index 000000000000..cf2d45946c57
--- /dev/null
+++ b/drivers/usb/host/whci/debug.c
@@ -0,0 +1,189 @@
1/*
2 * Wireless Host Controller (WHC) debug.
3 *
4 * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version
8 * 2 as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18#include <linux/kernel.h>
19#include <linux/debugfs.h>
20#include <linux/seq_file.h>
21
22#include "../../wusbcore/wusbhc.h"
23
24#include "whcd.h"
25
26struct whc_dbg {
27 struct dentry *di_f;
28 struct dentry *asl_f;
29 struct dentry *pzl_f;
30};
31
32void qset_print(struct seq_file *s, struct whc_qset *qset)
33{
34 struct whc_std *std;
35 struct urb *urb = NULL;
36 int i;
37
38 seq_printf(s, "qset %08x\n", (u32)qset->qset_dma);
39 seq_printf(s, " -> %08x\n", (u32)qset->qh.link);
40 seq_printf(s, " info: %08x %08x %08x\n",
41 qset->qh.info1, qset->qh.info2, qset->qh.info3);
42 seq_printf(s, " sts: %04x errs: %d\n", qset->qh.status, qset->qh.err_count);
43 seq_printf(s, " TD: sts: %08x opts: %08x\n",
44 qset->qh.overlay.qtd.status, qset->qh.overlay.qtd.options);
45
46 for (i = 0; i < WHCI_QSET_TD_MAX; i++) {
47 seq_printf(s, " %c%c TD[%d]: sts: %08x opts: %08x ptr: %08x\n",
48 i == qset->td_start ? 'S' : ' ',
49 i == qset->td_end ? 'E' : ' ',
50 i, qset->qtd[i].status, qset->qtd[i].options,
51 (u32)qset->qtd[i].page_list_ptr);
52 }
53 seq_printf(s, " ntds: %d\n", qset->ntds);
54 list_for_each_entry(std, &qset->stds, list_node) {
55 if (urb != std->urb) {
56 urb = std->urb;
57 seq_printf(s, " urb %p transferred: %d bytes\n", urb,
58 urb->actual_length);
59 }
60 if (std->qtd)
61 seq_printf(s, " sTD[%td]: %zu bytes @ %08x\n",
62 std->qtd - &qset->qtd[0],
63 std->len, std->num_pointers ?
64 (u32)(std->pl_virt[0].buf_ptr) : (u32)std->dma_addr);
65 else
66 seq_printf(s, " sTD[-]: %zd bytes @ %08x\n",
67 std->len, std->num_pointers ?
68 (u32)(std->pl_virt[0].buf_ptr) : (u32)std->dma_addr);
69 }
70}
71
72static int di_print(struct seq_file *s, void *p)
73{
74 struct whc *whc = s->private;
75 char buf[72];
76 int d;
77
78 for (d = 0; d < whc->n_devices; d++) {
79 struct di_buf_entry *di = &whc->di_buf[d];
80
81 bitmap_scnprintf(buf, sizeof(buf),
82 (unsigned long *)di->availability_info, UWB_NUM_MAS);
83
84 seq_printf(s, "DI[%d]\n", d);
85 seq_printf(s, " availability: %s\n", buf);
86 seq_printf(s, " %c%c key idx: %d dev addr: %d\n",
87 (di->addr_sec_info & WHC_DI_SECURE) ? 'S' : ' ',
88 (di->addr_sec_info & WHC_DI_DISABLE) ? 'D' : ' ',
89 (di->addr_sec_info & WHC_DI_KEY_IDX_MASK) >> 8,
90 (di->addr_sec_info & WHC_DI_DEV_ADDR_MASK));
91 }
92 return 0;
93}
94
95static int asl_print(struct seq_file *s, void *p)
96{
97 struct whc *whc = s->private;
98 struct whc_qset *qset;
99
100 list_for_each_entry(qset, &whc->async_list, list_node) {
101 qset_print(s, qset);
102 }
103
104 return 0;
105}
106
107static int pzl_print(struct seq_file *s, void *p)
108{
109 struct whc *whc = s->private;
110 struct whc_qset *qset;
111 int period;
112
113 for (period = 0; period < 5; period++) {
114 seq_printf(s, "Period %d\n", period);
115 list_for_each_entry(qset, &whc->periodic_list[period], list_node) {
116 qset_print(s, qset);
117 }
118 }
119 return 0;
120}
121
122static int di_open(struct inode *inode, struct file *file)
123{
124 return single_open(file, di_print, inode->i_private);
125}
126
127static int asl_open(struct inode *inode, struct file *file)
128{
129 return single_open(file, asl_print, inode->i_private);
130}
131
132static int pzl_open(struct inode *inode, struct file *file)
133{
134 return single_open(file, pzl_print, inode->i_private);
135}
136
137static struct file_operations di_fops = {
138 .open = di_open,
139 .read = seq_read,
140 .llseek = seq_lseek,
141 .release = single_release,
142 .owner = THIS_MODULE,
143};
144
145static struct file_operations asl_fops = {
146 .open = asl_open,
147 .read = seq_read,
148 .llseek = seq_lseek,
149 .release = single_release,
150 .owner = THIS_MODULE,
151};
152
153static struct file_operations pzl_fops = {
154 .open = pzl_open,
155 .read = seq_read,
156 .llseek = seq_lseek,
157 .release = single_release,
158 .owner = THIS_MODULE,
159};
160
161void whc_dbg_init(struct whc *whc)
162{
163 if (whc->wusbhc.pal.debugfs_dir == NULL)
164 return;
165
166 whc->dbg = kzalloc(sizeof(struct whc_dbg), GFP_KERNEL);
167 if (whc->dbg == NULL)
168 return;
169
170 whc->dbg->di_f = debugfs_create_file("di", 0444,
171 whc->wusbhc.pal.debugfs_dir, whc,
172 &di_fops);
173 whc->dbg->asl_f = debugfs_create_file("asl", 0444,
174 whc->wusbhc.pal.debugfs_dir, whc,
175 &asl_fops);
176 whc->dbg->pzl_f = debugfs_create_file("pzl", 0444,
177 whc->wusbhc.pal.debugfs_dir, whc,
178 &pzl_fops);
179}
180
181void whc_dbg_clean_up(struct whc *whc)
182{
183 if (whc->dbg) {
184 debugfs_remove(whc->dbg->pzl_f);
185 debugfs_remove(whc->dbg->asl_f);
186 debugfs_remove(whc->dbg->di_f);
187 kfree(whc->dbg);
188 }
189}
diff --git a/drivers/usb/host/whci/hcd.c b/drivers/usb/host/whci/hcd.c
index f599f89d3be1..1569afd6245b 100644
--- a/drivers/usb/host/whci/hcd.c
+++ b/drivers/usb/host/whci/hcd.c
@@ -273,6 +273,8 @@ static int whc_probe(struct umc_dev *umc)
273 goto error_wusbhc_b_create; 273 goto error_wusbhc_b_create;
274 } 274 }
275 275
276 whc_dbg_init(whc);
277
276 return 0; 278 return 0;
277 279
278error_wusbhc_b_create: 280error_wusbhc_b_create:
@@ -296,6 +298,7 @@ static void whc_remove(struct umc_dev *umc)
296 struct whc *whc = wusbhc_to_whc(wusbhc); 298 struct whc *whc = wusbhc_to_whc(wusbhc);
297 299
298 if (usb_hcd) { 300 if (usb_hcd) {
301 whc_dbg_clean_up(whc);
299 wusbhc_b_destroy(wusbhc); 302 wusbhc_b_destroy(wusbhc);
300 usb_remove_hcd(usb_hcd); 303 usb_remove_hcd(usb_hcd);
301 wusbhc_destroy(wusbhc); 304 wusbhc_destroy(wusbhc);
diff --git a/drivers/usb/host/whci/pzl.c b/drivers/usb/host/whci/pzl.c
index 34d3a0aeab2b..2ae5abf69a6a 100644
--- a/drivers/usb/host/whci/pzl.c
+++ b/drivers/usb/host/whci/pzl.c
@@ -19,35 +19,11 @@
19#include <linux/dma-mapping.h> 19#include <linux/dma-mapping.h>
20#include <linux/uwb/umc.h> 20#include <linux/uwb/umc.h>
21#include <linux/usb.h> 21#include <linux/usb.h>
22#define D_LOCAL 0
23#include <linux/uwb/debug.h>
24 22
25#include "../../wusbcore/wusbhc.h" 23#include "../../wusbcore/wusbhc.h"
26 24
27#include "whcd.h" 25#include "whcd.h"
28 26
29#if D_LOCAL >= 4
30static void dump_pzl(struct whc *whc, const char *tag)
31{
32 struct device *dev = &whc->umc->dev;
33 struct whc_qset *qset;
34 int period = 0;
35
36 d_printf(4, dev, "PZL %s\n", tag);
37
38 for (period = 0; period < 5; period++) {
39 d_printf(4, dev, "Period %d\n", period);
40 list_for_each_entry(qset, &whc->periodic_list[period], list_node) {
41 dump_qset(qset, dev);
42 }
43 }
44}
45#else
46static inline void dump_pzl(struct whc *whc, const char *tag)
47{
48}
49#endif
50
51static void update_pzl_pointers(struct whc *whc, int period, u64 addr) 27static void update_pzl_pointers(struct whc *whc, int period, u64 addr)
52{ 28{
53 switch (period) { 29 switch (period) {
@@ -250,8 +226,6 @@ void scan_periodic_work(struct work_struct *work)
250 226
251 spin_lock_irq(&whc->lock); 227 spin_lock_irq(&whc->lock);
252 228
253 dump_pzl(whc, "before processing");
254
255 for (period = 4; period >= 0; period--) { 229 for (period = 4; period >= 0; period--) {
256 list_for_each_entry_safe(qset, t, &whc->periodic_list[period], list_node) { 230 list_for_each_entry_safe(qset, t, &whc->periodic_list[period], list_node) {
257 if (!qset->in_hw_list) 231 if (!qset->in_hw_list)
@@ -263,8 +237,6 @@ void scan_periodic_work(struct work_struct *work)
263 if (update & (WHC_UPDATE_ADDED | WHC_UPDATE_REMOVED)) 237 if (update & (WHC_UPDATE_ADDED | WHC_UPDATE_REMOVED))
264 update_pzl_hw_view(whc); 238 update_pzl_hw_view(whc);
265 239
266 dump_pzl(whc, "after processing");
267
268 spin_unlock_irq(&whc->lock); 240 spin_unlock_irq(&whc->lock);
269 241
270 if (update) { 242 if (update) {
diff --git a/drivers/usb/host/whci/qset.c b/drivers/usb/host/whci/qset.c
index 0420037d2e18..7be74314ee12 100644
--- a/drivers/usb/host/whci/qset.c
+++ b/drivers/usb/host/whci/qset.c
@@ -24,46 +24,6 @@
24 24
25#include "whcd.h" 25#include "whcd.h"
26 26
27void dump_qset(struct whc_qset *qset, struct device *dev)
28{
29 struct whc_std *std;
30 struct urb *urb = NULL;
31 int i;
32
33 dev_dbg(dev, "qset %08x\n", (u32)qset->qset_dma);
34 dev_dbg(dev, " -> %08x\n", (u32)qset->qh.link);
35 dev_dbg(dev, " info: %08x %08x %08x\n",
36 qset->qh.info1, qset->qh.info2, qset->qh.info3);
37 dev_dbg(dev, " sts: %04x errs: %d\n", qset->qh.status, qset->qh.err_count);
38 dev_dbg(dev, " TD: sts: %08x opts: %08x\n",
39 qset->qh.overlay.qtd.status, qset->qh.overlay.qtd.options);
40
41 for (i = 0; i < WHCI_QSET_TD_MAX; i++) {
42 dev_dbg(dev, " %c%c TD[%d]: sts: %08x opts: %08x ptr: %08x\n",
43 i == qset->td_start ? 'S' : ' ',
44 i == qset->td_end ? 'E' : ' ',
45 i, qset->qtd[i].status, qset->qtd[i].options,
46 (u32)qset->qtd[i].page_list_ptr);
47 }
48 dev_dbg(dev, " ntds: %d\n", qset->ntds);
49 list_for_each_entry(std, &qset->stds, list_node) {
50 if (urb != std->urb) {
51 urb = std->urb;
52 dev_dbg(dev, " urb %p transferred: %d bytes\n", urb,
53 urb->actual_length);
54 }
55 if (std->qtd)
56 dev_dbg(dev, " sTD[%td]: %zu bytes @ %08x\n",
57 std->qtd - &qset->qtd[0],
58 std->len, std->num_pointers ?
59 (u32)(std->pl_virt[0].buf_ptr) : (u32)std->dma_addr);
60 else
61 dev_dbg(dev, " sTD[-]: %zd bytes @ %08x\n",
62 std->len, std->num_pointers ?
63 (u32)(std->pl_virt[0].buf_ptr) : (u32)std->dma_addr);
64 }
65}
66
67struct whc_qset *qset_alloc(struct whc *whc, gfp_t mem_flags) 27struct whc_qset *qset_alloc(struct whc *whc, gfp_t mem_flags)
68{ 28{
69 struct whc_qset *qset; 29 struct whc_qset *qset;
diff --git a/drivers/usb/host/whci/whcd.h b/drivers/usb/host/whci/whcd.h
index 1bbb8cb6bf80..0f3540f04f53 100644
--- a/drivers/usb/host/whci/whcd.h
+++ b/drivers/usb/host/whci/whcd.h
@@ -21,6 +21,7 @@
21#define __WHCD_H 21#define __WHCD_H
22 22
23#include <linux/uwb/whci.h> 23#include <linux/uwb/whci.h>
24#include <linux/uwb/umc.h>
24#include <linux/workqueue.h> 25#include <linux/workqueue.h>
25 26
26#include "whci-hc.h" 27#include "whci-hc.h"
@@ -28,6 +29,7 @@
28/* Generic command timeout. */ 29/* Generic command timeout. */
29#define WHC_GENCMD_TIMEOUT_MS 100 30#define WHC_GENCMD_TIMEOUT_MS 100
30 31
32struct whc_dbg;
31 33
32struct whc { 34struct whc {
33 struct wusbhc wusbhc; 35 struct wusbhc wusbhc;
@@ -69,6 +71,8 @@ struct whc {
69 struct list_head periodic_removed_list; 71 struct list_head periodic_removed_list;
70 wait_queue_head_t periodic_list_wq; 72 wait_queue_head_t periodic_list_wq;
71 struct work_struct periodic_work; 73 struct work_struct periodic_work;
74
75 struct whc_dbg *dbg;
72}; 76};
73 77
74#define wusbhc_to_whc(w) (container_of((w), struct whc, wusbhc)) 78#define wusbhc_to_whc(w) (container_of((w), struct whc, wusbhc))
@@ -190,8 +194,11 @@ void process_inactive_qtd(struct whc *whc, struct whc_qset *qset,
190 struct whc_qtd *qtd); 194 struct whc_qtd *qtd);
191enum whc_update qset_add_qtds(struct whc *whc, struct whc_qset *qset); 195enum whc_update qset_add_qtds(struct whc *whc, struct whc_qset *qset);
192void qset_remove_complete(struct whc *whc, struct whc_qset *qset); 196void qset_remove_complete(struct whc *whc, struct whc_qset *qset);
193void dump_qset(struct whc_qset *qset, struct device *dev);
194void pzl_update(struct whc *whc, uint32_t wusbcmd); 197void pzl_update(struct whc *whc, uint32_t wusbcmd);
195void asl_update(struct whc *whc, uint32_t wusbcmd); 198void asl_update(struct whc *whc, uint32_t wusbcmd);
196 199
200/* debug.c */
201void whc_dbg_init(struct whc *whc);
202void whc_dbg_clean_up(struct whc *whc);
203
197#endif /* #ifndef __WHCD_H */ 204#endif /* #ifndef __WHCD_H */
diff --git a/drivers/usb/host/whci/wusb.c b/drivers/usb/host/whci/wusb.c
index 540021a0971e..f24efdebad17 100644
--- a/drivers/usb/host/whci/wusb.c
+++ b/drivers/usb/host/whci/wusb.c
@@ -18,43 +18,16 @@
18#include <linux/kernel.h> 18#include <linux/kernel.h>
19#include <linux/init.h> 19#include <linux/init.h>
20#include <linux/uwb/umc.h> 20#include <linux/uwb/umc.h>
21#define D_LOCAL 1
22#include <linux/uwb/debug.h>
23 21
24#include "../../wusbcore/wusbhc.h" 22#include "../../wusbcore/wusbhc.h"
25 23
26#include "whcd.h" 24#include "whcd.h"
27 25
28#if D_LOCAL >= 1
29static void dump_di(struct whc *whc, int idx)
30{
31 struct di_buf_entry *di = &whc->di_buf[idx];
32 struct device *dev = &whc->umc->dev;
33 char buf[128];
34
35 bitmap_scnprintf(buf, sizeof(buf), (unsigned long *)di->availability_info, UWB_NUM_MAS);
36
37 d_printf(1, dev, "DI[%d]\n", idx);
38 d_printf(1, dev, " availability: %s\n", buf);
39 d_printf(1, dev, " %c%c key idx: %d dev addr: %d\n",
40 (di->addr_sec_info & WHC_DI_SECURE) ? 'S' : ' ',
41 (di->addr_sec_info & WHC_DI_DISABLE) ? 'D' : ' ',
42 (di->addr_sec_info & WHC_DI_KEY_IDX_MASK) >> 8,
43 (di->addr_sec_info & WHC_DI_DEV_ADDR_MASK));
44}
45#else
46static inline void dump_di(struct whc *whc, int idx)
47{
48}
49#endif
50
51static int whc_update_di(struct whc *whc, int idx) 26static int whc_update_di(struct whc *whc, int idx)
52{ 27{
53 int offset = idx / 32; 28 int offset = idx / 32;
54 u32 bit = 1 << (idx % 32); 29 u32 bit = 1 << (idx % 32);
55 30
56 dump_di(whc, idx);
57
58 le_writel(bit, whc->base + WUSBDIBUPDATED + offset); 31 le_writel(bit, whc->base + WUSBDIBUPDATED + offset);
59 32
60 return whci_wait_for(&whc->umc->dev, 33 return whci_wait_for(&whc->umc->dev,
diff --git a/drivers/uwb/pal.c b/drivers/uwb/pal.c
index 605765124f5b..99a19c199095 100644
--- a/drivers/uwb/pal.c
+++ b/drivers/uwb/pal.c
@@ -16,6 +16,7 @@
16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */ 17 */
18#include <linux/kernel.h> 18#include <linux/kernel.h>
19#include <linux/debugfs.h>
19#include <linux/uwb.h> 20#include <linux/uwb.h>
20 21
21#include "uwb-internal.h" 22#include "uwb-internal.h"
@@ -54,6 +55,8 @@ int uwb_pal_register(struct uwb_pal *pal)
54 } 55 }
55 } 56 }
56 57
58 pal->debugfs_dir = uwb_dbg_create_pal_dir(pal);
59
57 mutex_lock(&rc->uwb_dev.mutex); 60 mutex_lock(&rc->uwb_dev.mutex);
58 list_add(&pal->node, &rc->pals); 61 list_add(&pal->node, &rc->pals);
59 mutex_unlock(&rc->uwb_dev.mutex); 62 mutex_unlock(&rc->uwb_dev.mutex);
@@ -76,6 +79,8 @@ void uwb_pal_unregister(struct uwb_pal *pal)
76 list_del(&pal->node); 79 list_del(&pal->node);
77 mutex_unlock(&rc->uwb_dev.mutex); 80 mutex_unlock(&rc->uwb_dev.mutex);
78 81
82 debugfs_remove(pal->debugfs_dir);
83
79 if (pal->device) { 84 if (pal->device) {
80 sysfs_remove_link(&rc->uwb_dev.dev.kobj, pal->name); 85 sysfs_remove_link(&rc->uwb_dev.dev.kobj, pal->name);
81 sysfs_remove_link(&pal->device->kobj, "uwb_rc"); 86 sysfs_remove_link(&pal->device->kobj, "uwb_rc");
diff --git a/drivers/uwb/uwb-debug.c b/drivers/uwb/uwb-debug.c
index ec1b7a403ff3..a6debb9baf38 100644
--- a/drivers/uwb/uwb-debug.c
+++ b/drivers/uwb/uwb-debug.c
@@ -407,3 +407,16 @@ void uwb_dbg_exit(void)
407{ 407{
408 debugfs_remove(root_dir); 408 debugfs_remove(root_dir);
409} 409}
410
411/**
412 * uwb_dbg_create_pal_dir - create a debugfs directory for a PAL
413 * @pal: The PAL.
414 */
415struct dentry *uwb_dbg_create_pal_dir(struct uwb_pal *pal)
416{
417 struct uwb_rc *rc = pal->rc;
418
419 if (root_dir && rc->dbg && rc->dbg->root_d && pal->name)
420 return debugfs_create_dir(pal->name, rc->dbg->root_d);
421 return NULL;
422}
diff --git a/drivers/uwb/uwb-internal.h b/drivers/uwb/uwb-internal.h
index 9c0cdb4ded0c..f0f21f406bf0 100644
--- a/drivers/uwb/uwb-internal.h
+++ b/drivers/uwb/uwb-internal.h
@@ -284,8 +284,7 @@ void uwb_dbg_init(void);
284void uwb_dbg_exit(void); 284void uwb_dbg_exit(void);
285void uwb_dbg_add_rc(struct uwb_rc *rc); 285void uwb_dbg_add_rc(struct uwb_rc *rc);
286void uwb_dbg_del_rc(struct uwb_rc *rc); 286void uwb_dbg_del_rc(struct uwb_rc *rc);
287 287struct dentry *uwb_dbg_create_pal_dir(struct uwb_pal *pal);
288/* Workarounds for version specific stuff */
289 288
290static inline void uwb_dev_lock(struct uwb_dev *uwb_dev) 289static inline void uwb_dev_lock(struct uwb_dev *uwb_dev)
291{ 290{
diff --git a/include/linux/uwb.h b/include/linux/uwb.h
index 1719709d60ca..d7ed5201ade6 100644
--- a/include/linux/uwb.h
+++ b/include/linux/uwb.h
@@ -394,6 +394,8 @@ struct uwb_rc {
394 * @channel: channel being used by the PAL; 0 if the PAL isn't using 394 * @channel: channel being used by the PAL; 0 if the PAL isn't using
395 * the radio; -1 if the PAL wishes to use the radio but 395 * the radio; -1 if the PAL wishes to use the radio but
396 * cannot. 396 * cannot.
397 * @debugfs_dir: a debugfs directory which the PAL can use for its own
398 * debugfs files.
397 * 399 *
398 * A Protocol Adaptation Layer (PAL) is a user of the WiMedia UWB 400 * A Protocol Adaptation Layer (PAL) is a user of the WiMedia UWB
399 * radio platform (e.g., WUSB, WLP or Bluetooth UWB AMP). 401 * radio platform (e.g., WUSB, WLP or Bluetooth UWB AMP).
@@ -418,6 +420,7 @@ struct uwb_pal {
418 void (*new_rsv)(struct uwb_pal *pal, struct uwb_rsv *rsv); 420 void (*new_rsv)(struct uwb_pal *pal, struct uwb_rsv *rsv);
419 421
420 int channel; 422 int channel;
423 struct dentry *debugfs_dir;
421}; 424};
422 425
423void uwb_pal_init(struct uwb_pal *pal); 426void uwb_pal_init(struct uwb_pal *pal);