aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host')
-rw-r--r--drivers/usb/host/hwa-hc.c104
-rw-r--r--drivers/usb/host/whci/Kbuild1
-rw-r--r--drivers/usb/host/whci/asl.c46
-rw-r--r--drivers/usb/host/whci/debug.c189
-rw-r--r--drivers/usb/host/whci/hcd.c6
-rw-r--r--drivers/usb/host/whci/hw.c8
-rw-r--r--drivers/usb/host/whci/int.c1
-rw-r--r--drivers/usb/host/whci/pzl.c49
-rw-r--r--drivers/usb/host/whci/qset.c40
-rw-r--r--drivers/usb/host/whci/whcd.h11
-rw-r--r--drivers/usb/host/whci/whci-hc.h2
-rw-r--r--drivers/usb/host/whci/wusb.c43
12 files changed, 305 insertions, 195 deletions
diff --git a/drivers/usb/host/hwa-hc.c b/drivers/usb/host/hwa-hc.c
index 64be4d88df11..2a4d36fa70b0 100644
--- a/drivers/usb/host/hwa-hc.c
+++ b/drivers/usb/host/hwa-hc.c
@@ -54,7 +54,6 @@
54 * DWA). 54 * DWA).
55 */ 55 */
56#include <linux/kernel.h> 56#include <linux/kernel.h>
57#include <linux/version.h>
58#include <linux/init.h> 57#include <linux/init.h>
59#include <linux/module.h> 58#include <linux/module.h>
60#include <linux/workqueue.h> 59#include <linux/workqueue.h>
@@ -171,11 +170,6 @@ static int hwahc_op_start(struct usb_hcd *usb_hcd)
171 if (result < 0) 170 if (result < 0)
172 goto error_set_cluster_id; 171 goto error_set_cluster_id;
173 172
174 result = wa_nep_arm(&hwahc->wa, GFP_KERNEL);
175 if (result < 0) {
176 dev_err(dev, "cannot listen to notifications: %d\n", result);
177 goto error_stop;
178 }
179 usb_hcd->uses_new_polling = 1; 173 usb_hcd->uses_new_polling = 1;
180 usb_hcd->poll_rh = 1; 174 usb_hcd->poll_rh = 1;
181 usb_hcd->state = HC_STATE_RUNNING; 175 usb_hcd->state = HC_STATE_RUNNING;
@@ -185,8 +179,6 @@ out:
185 d_fnend(4, dev, "(hwahc %p) = %d\n", hwahc, result); 179 d_fnend(4, dev, "(hwahc %p) = %d\n", hwahc, result);
186 return result; 180 return result;
187 181
188error_stop:
189 __wa_stop(&hwahc->wa);
190error_set_cluster_id: 182error_set_cluster_id:
191 wusb_cluster_id_put(wusbhc->cluster_id); 183 wusb_cluster_id_put(wusbhc->cluster_id);
192error_cluster_id_get: 184error_cluster_id_get:
@@ -194,39 +186,6 @@ error_cluster_id_get:
194 186
195} 187}
196 188
197/*
198 * FIXME: break this function up
199 */
200static int __hwahc_op_wusbhc_start(struct wusbhc *wusbhc)
201{
202 int result;
203 struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
204 struct device *dev = &hwahc->wa.usb_iface->dev;
205
206 /* Set up a Host Info WUSB Information Element */
207 d_fnstart(4, dev, "(hwahc %p)\n", hwahc);
208 result = -ENOSPC;
209
210 result = __wa_set_feature(&hwahc->wa, WA_ENABLE);
211 if (result < 0) {
212 dev_err(dev, "error commanding HC to start: %d\n", result);
213 goto error_stop;
214 }
215 result = __wa_wait_status(&hwahc->wa, WA_ENABLE, WA_ENABLE);
216 if (result < 0) {
217 dev_err(dev, "error waiting for HC to start: %d\n", result);
218 goto error_stop;
219 }
220 result = 0;
221out:
222 d_fnend(4, dev, "(hwahc %p) = %d\n", hwahc, result);
223 return result;
224
225error_stop:
226 result = __wa_clear_feature(&hwahc->wa, WA_ENABLE);
227 goto out;
228}
229
230static int hwahc_op_suspend(struct usb_hcd *usb_hcd, pm_message_t msg) 189static int hwahc_op_suspend(struct usb_hcd *usb_hcd, pm_message_t msg)
231{ 190{
232 struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); 191 struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
@@ -246,18 +205,6 @@ static int hwahc_op_resume(struct usb_hcd *usb_hcd)
246 return -ENOSYS; 205 return -ENOSYS;
247} 206}
248 207
249static void __hwahc_op_wusbhc_stop(struct wusbhc *wusbhc)
250{
251 int result;
252 struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
253 struct device *dev = &hwahc->wa.usb_iface->dev;
254
255 d_fnstart(4, dev, "(hwahc %p)\n", hwahc);
256 /* Nothing for now */
257 d_fnend(4, dev, "(hwahc %p) = %d\n", hwahc, result);
258 return;
259}
260
261/* 208/*
262 * No need to abort pipes, as when this is called, all the children 209 * No need to abort pipes, as when this is called, all the children
263 * has been disconnected and that has done it [through 210 * has been disconnected and that has done it [through
@@ -274,9 +221,6 @@ static void hwahc_op_stop(struct usb_hcd *usb_hcd)
274 221
275 d_fnstart(4, dev, "(hwahc %p)\n", hwahc); 222 d_fnstart(4, dev, "(hwahc %p)\n", hwahc);
276 mutex_lock(&wusbhc->mutex); 223 mutex_lock(&wusbhc->mutex);
277 wusbhc_stop(wusbhc);
278 wa_nep_disarm(&hwahc->wa);
279 result = __wa_stop(&hwahc->wa);
280 wusb_cluster_id_put(wusbhc->cluster_id); 224 wusb_cluster_id_put(wusbhc->cluster_id);
281 mutex_unlock(&wusbhc->mutex); 225 mutex_unlock(&wusbhc->mutex);
282 d_fnend(4, dev, "(hwahc %p) = %d\n", hwahc, result); 226 d_fnend(4, dev, "(hwahc %p) = %d\n", hwahc, result);
@@ -325,6 +269,54 @@ static void hwahc_op_endpoint_disable(struct usb_hcd *usb_hcd,
325 rpipe_ep_disable(&hwahc->wa, ep); 269 rpipe_ep_disable(&hwahc->wa, ep);
326} 270}
327 271
272static int __hwahc_op_wusbhc_start(struct wusbhc *wusbhc)
273{
274 int result;
275 struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
276 struct device *dev = &hwahc->wa.usb_iface->dev;
277
278 result = __wa_set_feature(&hwahc->wa, WA_ENABLE);
279 if (result < 0) {
280 dev_err(dev, "error commanding HC to start: %d\n", result);
281 goto error_stop;
282 }
283 result = __wa_wait_status(&hwahc->wa, WA_ENABLE, WA_ENABLE);
284 if (result < 0) {
285 dev_err(dev, "error waiting for HC to start: %d\n", result);
286 goto error_stop;
287 }
288 result = wa_nep_arm(&hwahc->wa, GFP_KERNEL);
289 if (result < 0) {
290 dev_err(dev, "cannot listen to notifications: %d\n", result);
291 goto error_stop;
292 }
293 return result;
294
295error_stop:
296 __wa_clear_feature(&hwahc->wa, WA_ENABLE);
297 return result;
298}
299
300static void __hwahc_op_wusbhc_stop(struct wusbhc *wusbhc, int delay)
301{
302 struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
303 struct wahc *wa = &hwahc->wa;
304 u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber;
305 int ret;
306
307 ret = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
308 WUSB_REQ_CHAN_STOP,
309 USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
310 delay * 1000,
311 iface_no,
312 NULL, 0, 1000 /* FIXME: arbitrary */);
313 if (ret == 0)
314 msleep(delay);
315
316 wa_nep_disarm(&hwahc->wa);
317 __wa_stop(&hwahc->wa);
318}
319
328/* 320/*
329 * Set the UWB MAS allocation for the WUSB cluster 321 * Set the UWB MAS allocation for the WUSB cluster
330 * 322 *
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 4d7078e50572..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{
@@ -179,11 +158,26 @@ void asl_stop(struct whc *whc)
179 1000, "stop ASL"); 158 1000, "stop ASL");
180} 159}
181 160
161/**
162 * asl_update - request an ASL update and wait for the hardware to be synced
163 * @whc: the WHCI HC
164 * @wusbcmd: WUSBCMD value to start the update.
165 *
166 * If the WUSB HC is inactive (i.e., the ASL is stopped) then the
167 * update must be skipped as the hardware may not respond to update
168 * requests.
169 */
182void asl_update(struct whc *whc, uint32_t wusbcmd) 170void asl_update(struct whc *whc, uint32_t wusbcmd)
183{ 171{
184 whc_write_wusbcmd(whc, wusbcmd, wusbcmd); 172 struct wusbhc *wusbhc = &whc->wusbhc;
185 wait_event(whc->async_list_wq, 173
186 (le_readl(whc->base + WUSBCMD) & WUSBCMD_ASYNC_UPDATED) == 0); 174 mutex_lock(&wusbhc->mutex);
175 if (wusbhc->active) {
176 whc_write_wusbcmd(whc, wusbcmd, wusbcmd);
177 wait_event(whc->async_list_wq,
178 (le_readl(whc->base + WUSBCMD) & WUSBCMD_ASYNC_UPDATED) == 0);
179 }
180 mutex_unlock(&wusbhc->mutex);
187} 181}
188 182
189/** 183/**
@@ -202,8 +196,6 @@ void scan_async_work(struct work_struct *work)
202 196
203 spin_lock_irq(&whc->lock); 197 spin_lock_irq(&whc->lock);
204 198
205 dump_asl(whc, "before processing");
206
207 /* 199 /*
208 * Transerve the software list backwards so new qsets can be 200 * Transerve the software list backwards so new qsets can be
209 * safely inserted into the ASL without making it non-circular. 201 * safely inserted into the ASL without making it non-circular.
@@ -217,8 +209,6 @@ void scan_async_work(struct work_struct *work)
217 update |= process_qset(whc, qset); 209 update |= process_qset(whc, qset);
218 } 210 }
219 211
220 dump_asl(whc, "after processing");
221
222 spin_unlock_irq(&whc->lock); 212 spin_unlock_irq(&whc->lock);
223 213
224 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 ef3ad4dca945..1569afd6245b 100644
--- a/drivers/usb/host/whci/hcd.c
+++ b/drivers/usb/host/whci/hcd.c
@@ -15,7 +15,6 @@
15 * You should have received a copy of the GNU General Public License 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/>. 16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */ 17 */
18#include <linux/version.h>
19#include <linux/kernel.h> 18#include <linux/kernel.h>
20#include <linux/init.h> 19#include <linux/init.h>
21#include <linux/uwb/umc.h> 20#include <linux/uwb/umc.h>
@@ -92,8 +91,6 @@ static void whc_stop(struct usb_hcd *usb_hcd)
92 91
93 mutex_lock(&wusbhc->mutex); 92 mutex_lock(&wusbhc->mutex);
94 93
95 wusbhc_stop(wusbhc);
96
97 /* stop HC */ 94 /* stop HC */
98 le_writel(0, whc->base + WUSBINTR); 95 le_writel(0, whc->base + WUSBINTR);
99 whc_write_wusbcmd(whc, WUSBCMD_RUN, 0); 96 whc_write_wusbcmd(whc, WUSBCMD_RUN, 0);
@@ -276,6 +273,8 @@ static int whc_probe(struct umc_dev *umc)
276 goto error_wusbhc_b_create; 273 goto error_wusbhc_b_create;
277 } 274 }
278 275
276 whc_dbg_init(whc);
277
279 return 0; 278 return 0;
280 279
281error_wusbhc_b_create: 280error_wusbhc_b_create:
@@ -299,6 +298,7 @@ static void whc_remove(struct umc_dev *umc)
299 struct whc *whc = wusbhc_to_whc(wusbhc); 298 struct whc *whc = wusbhc_to_whc(wusbhc);
300 299
301 if (usb_hcd) { 300 if (usb_hcd) {
301 whc_dbg_clean_up(whc);
302 wusbhc_b_destroy(wusbhc); 302 wusbhc_b_destroy(wusbhc);
303 usb_remove_hcd(usb_hcd); 303 usb_remove_hcd(usb_hcd);
304 wusbhc_destroy(wusbhc); 304 wusbhc_destroy(wusbhc);
diff --git a/drivers/usb/host/whci/hw.c b/drivers/usb/host/whci/hw.c
index ac86e59c1225..d498e7203217 100644
--- a/drivers/usb/host/whci/hw.c
+++ b/drivers/usb/host/whci/hw.c
@@ -50,6 +50,7 @@ int whc_do_gencmd(struct whc *whc, u32 cmd, u32 params, void *addr, size_t len)
50 unsigned long flags; 50 unsigned long flags;
51 dma_addr_t dma_addr; 51 dma_addr_t dma_addr;
52 int t; 52 int t;
53 int ret = 0;
53 54
54 mutex_lock(&whc->mutex); 55 mutex_lock(&whc->mutex);
55 56
@@ -61,7 +62,8 @@ int whc_do_gencmd(struct whc *whc, u32 cmd, u32 params, void *addr, size_t len)
61 dev_err(&whc->umc->dev, "generic command timeout (%04x/%04x)\n", 62 dev_err(&whc->umc->dev, "generic command timeout (%04x/%04x)\n",
62 le_readl(whc->base + WUSBGENCMDSTS), 63 le_readl(whc->base + WUSBGENCMDSTS),
63 le_readl(whc->base + WUSBGENCMDPARAMS)); 64 le_readl(whc->base + WUSBGENCMDPARAMS));
64 return -ETIMEDOUT; 65 ret = -ETIMEDOUT;
66 goto out;
65 } 67 }
66 68
67 if (addr) { 69 if (addr) {
@@ -80,8 +82,8 @@ int whc_do_gencmd(struct whc *whc, u32 cmd, u32 params, void *addr, size_t len)
80 whc->base + WUSBGENCMDSTS); 82 whc->base + WUSBGENCMDSTS);
81 83
82 spin_unlock_irqrestore(&whc->lock, flags); 84 spin_unlock_irqrestore(&whc->lock, flags);
83 85out:
84 mutex_unlock(&whc->mutex); 86 mutex_unlock(&whc->mutex);
85 87
86 return 0; 88 return ret;
87} 89}
diff --git a/drivers/usb/host/whci/int.c b/drivers/usb/host/whci/int.c
index fce01174aa9b..6aae70028101 100644
--- a/drivers/usb/host/whci/int.c
+++ b/drivers/usb/host/whci/int.c
@@ -15,7 +15,6 @@
15 * You should have received a copy of the GNU General Public License 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/>. 16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */ 17 */
18#include <linux/version.h>
19#include <linux/kernel.h> 18#include <linux/kernel.h>
20#include <linux/init.h> 19#include <linux/init.h>
21#include <linux/uwb/umc.h> 20#include <linux/uwb/umc.h>
diff --git a/drivers/usb/host/whci/pzl.c b/drivers/usb/host/whci/pzl.c
index 8d62df0c330b..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) {
@@ -195,11 +171,26 @@ void pzl_stop(struct whc *whc)
195 1000, "stop PZL"); 171 1000, "stop PZL");
196} 172}
197 173
174/**
175 * pzl_update - request a PZL update and wait for the hardware to be synced
176 * @whc: the WHCI HC
177 * @wusbcmd: WUSBCMD value to start the update.
178 *
179 * If the WUSB HC is inactive (i.e., the PZL is stopped) then the
180 * update must be skipped as the hardware may not respond to update
181 * requests.
182 */
198void pzl_update(struct whc *whc, uint32_t wusbcmd) 183void pzl_update(struct whc *whc, uint32_t wusbcmd)
199{ 184{
200 whc_write_wusbcmd(whc, wusbcmd, wusbcmd); 185 struct wusbhc *wusbhc = &whc->wusbhc;
201 wait_event(whc->periodic_list_wq, 186
202 (le_readl(whc->base + WUSBCMD) & WUSBCMD_PERIODIC_UPDATED) == 0); 187 mutex_lock(&wusbhc->mutex);
188 if (wusbhc->active) {
189 whc_write_wusbcmd(whc, wusbcmd, wusbcmd);
190 wait_event(whc->periodic_list_wq,
191 (le_readl(whc->base + WUSBCMD) & WUSBCMD_PERIODIC_UPDATED) == 0);
192 }
193 mutex_unlock(&wusbhc->mutex);
203} 194}
204 195
205static void update_pzl_hw_view(struct whc *whc) 196static void update_pzl_hw_view(struct whc *whc)
@@ -235,8 +226,6 @@ void scan_periodic_work(struct work_struct *work)
235 226
236 spin_lock_irq(&whc->lock); 227 spin_lock_irq(&whc->lock);
237 228
238 dump_pzl(whc, "before processing");
239
240 for (period = 4; period >= 0; period--) { 229 for (period = 4; period >= 0; period--) {
241 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) {
242 if (!qset->in_hw_list) 231 if (!qset->in_hw_list)
@@ -248,8 +237,6 @@ void scan_periodic_work(struct work_struct *work)
248 if (update & (WHC_UPDATE_ADDED | WHC_UPDATE_REMOVED)) 237 if (update & (WHC_UPDATE_ADDED | WHC_UPDATE_REMOVED))
249 update_pzl_hw_view(whc); 238 update_pzl_hw_view(whc);
250 239
251 dump_pzl(whc, "after processing");
252
253 spin_unlock_irq(&whc->lock); 240 spin_unlock_irq(&whc->lock);
254 241
255 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 1d2a53bd39fd..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))
@@ -136,7 +140,7 @@ int whc_do_gencmd(struct whc *whc, u32 cmd, u32 params, void *addr, size_t len);
136 140
137/* wusb.c */ 141/* wusb.c */
138int whc_wusbhc_start(struct wusbhc *wusbhc); 142int whc_wusbhc_start(struct wusbhc *wusbhc);
139void whc_wusbhc_stop(struct wusbhc *wusbhc); 143void whc_wusbhc_stop(struct wusbhc *wusbhc, int delay);
140int whc_mmcie_add(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt, 144int whc_mmcie_add(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt,
141 u8 handle, struct wuie_hdr *wuie); 145 u8 handle, struct wuie_hdr *wuie);
142int whc_mmcie_rm(struct wusbhc *wusbhc, u8 handle); 146int whc_mmcie_rm(struct wusbhc *wusbhc, u8 handle);
@@ -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/whci-hc.h b/drivers/usb/host/whci/whci-hc.h
index bff1eb7a35cf..51df7e313b38 100644
--- a/drivers/usb/host/whci/whci-hc.h
+++ b/drivers/usb/host/whci/whci-hc.h
@@ -410,6 +410,8 @@ struct dn_buf_entry {
410# define WUSBDNTSCTRL_SLOTS(s) ((s) << 0) 410# define WUSBDNTSCTRL_SLOTS(s) ((s) << 0)
411 411
412#define WUSBTIME 0x68 412#define WUSBTIME 0x68
413# define WUSBTIME_CHANNEL_TIME_MASK 0x00ffffff
414
413#define WUSBBPST 0x6c 415#define WUSBBPST 0x6c
414#define WUSBDIBUPDATED 0x70 416#define WUSBDIBUPDATED 0x70
415 417
diff --git a/drivers/usb/host/whci/wusb.c b/drivers/usb/host/whci/wusb.c
index 66e4ddcd961d..f24efdebad17 100644
--- a/drivers/usb/host/whci/wusb.c
+++ b/drivers/usb/host/whci/wusb.c
@@ -15,47 +15,19 @@
15 * You should have received a copy of the GNU General Public License 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/>. 16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */ 17 */
18#include <linux/version.h>
19#include <linux/kernel.h> 18#include <linux/kernel.h>
20#include <linux/init.h> 19#include <linux/init.h>
21#include <linux/uwb/umc.h> 20#include <linux/uwb/umc.h>
22#define D_LOCAL 1
23#include <linux/uwb/debug.h>
24 21
25#include "../../wusbcore/wusbhc.h" 22#include "../../wusbcore/wusbhc.h"
26 23
27#include "whcd.h" 24#include "whcd.h"
28 25
29#if D_LOCAL >= 1
30static void dump_di(struct whc *whc, int idx)
31{
32 struct di_buf_entry *di = &whc->di_buf[idx];
33 struct device *dev = &whc->umc->dev;
34 char buf[128];
35
36 bitmap_scnprintf(buf, sizeof(buf), (unsigned long *)di->availability_info, UWB_NUM_MAS);
37
38 d_printf(1, dev, "DI[%d]\n", idx);
39 d_printf(1, dev, " availability: %s\n", buf);
40 d_printf(1, dev, " %c%c key idx: %d dev addr: %d\n",
41 (di->addr_sec_info & WHC_DI_SECURE) ? 'S' : ' ',
42 (di->addr_sec_info & WHC_DI_DISABLE) ? 'D' : ' ',
43 (di->addr_sec_info & WHC_DI_KEY_IDX_MASK) >> 8,
44 (di->addr_sec_info & WHC_DI_DEV_ADDR_MASK));
45}
46#else
47static inline void dump_di(struct whc *whc, int idx)
48{
49}
50#endif
51
52static int whc_update_di(struct whc *whc, int idx) 26static int whc_update_di(struct whc *whc, int idx)
53{ 27{
54 int offset = idx / 32; 28 int offset = idx / 32;
55 u32 bit = 1 << (idx % 32); 29 u32 bit = 1 << (idx % 32);
56 30
57 dump_di(whc, idx);
58
59 le_writel(bit, whc->base + WUSBDIBUPDATED + offset); 31 le_writel(bit, whc->base + WUSBDIBUPDATED + offset);
60 32
61 return whci_wait_for(&whc->umc->dev, 33 return whci_wait_for(&whc->umc->dev,
@@ -64,8 +36,9 @@ static int whc_update_di(struct whc *whc, int idx)
64} 36}
65 37
66/* 38/*
67 * WHCI starts and stops MMCs based on there being a valid GTK so 39 * WHCI starts MMCs based on there being a valid GTK so these need
68 * these need only start/stop the asynchronous and periodic schedules. 40 * only start/stop the asynchronous and periodic schedules and send a
41 * channel stop command.
69 */ 42 */
70 43
71int whc_wusbhc_start(struct wusbhc *wusbhc) 44int whc_wusbhc_start(struct wusbhc *wusbhc)
@@ -78,12 +51,20 @@ int whc_wusbhc_start(struct wusbhc *wusbhc)
78 return 0; 51 return 0;
79} 52}
80 53
81void whc_wusbhc_stop(struct wusbhc *wusbhc) 54void whc_wusbhc_stop(struct wusbhc *wusbhc, int delay)
82{ 55{
83 struct whc *whc = wusbhc_to_whc(wusbhc); 56 struct whc *whc = wusbhc_to_whc(wusbhc);
57 u32 stop_time, now_time;
58 int ret;
84 59
85 pzl_stop(whc); 60 pzl_stop(whc);
86 asl_stop(whc); 61 asl_stop(whc);
62
63 now_time = le_readl(whc->base + WUSBTIME) & WUSBTIME_CHANNEL_TIME_MASK;
64 stop_time = (now_time + ((delay * 8) << 7)) & 0x00ffffff;
65 ret = whc_do_gencmd(whc, WUSBGENCMDSTS_CHAN_STOP, stop_time, NULL, 0);
66 if (ret == 0)
67 msleep(delay);
87} 68}
88 69
89int whc_mmcie_add(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt, 70int whc_mmcie_add(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt,