]>
Commit | Line | Data |
---|---|---|
2cb7cef9 BS |
1 | From 5c05917e7fe313a187ad6ebb94c1c6cf42862a0b Mon Sep 17 00:00:00 2001 |
2 | From: Yinghai Lu <yhlu.kernel@gmail.com> | |
3 | Date: Thu, 24 Jul 2008 17:29:40 -0700 | |
4 | Subject: x86: usb debug port early console, v4 | |
5 | Patch-mainline: 2.6.28 | |
6 | ||
7 | From: Yinghai Lu <yhlu.kernel@gmail.com> | |
8 | ||
9 | commit 5c05917e7fe313a187ad6ebb94c1c6cf42862a0b upstream. | |
10 | ||
11 | based on work from Eric, and add some timeout so don't dead loop when debug | |
12 | device is not installed | |
13 | ||
14 | v2: fix checkpatch warning | |
15 | v3: move ehci struct def to linux/usrb/ehci_def.h from host/ehci.h | |
16 | also add CONFIG_EARLY_PRINTK_DBGP to disable it by default | |
17 | v4: address comments from Ingo, seperate ehci reg def moving to another patch | |
18 | also add auto detect port that connect to debug device for Nvidia | |
19 | southbridge | |
20 | ||
21 | Signed-off-by: Yinghai Lu <yhlu.kernel@gmail.com> | |
22 | Cc: Andrew Morton <akpm@linux-foundation.org> | |
23 | Cc: Andi Kleen <andi@firstfloor.org> | |
24 | Cc: "Arjan van de Ven" <arjan@infradead.org> | |
25 | Cc: "Eric W. Biederman" <ebiederm@xmission.com> | |
26 | Cc: "Greg KH" <greg@kroah.com> | |
27 | Signed-off-by: Ingo Molnar <mingo@elte.hu> | |
28 | Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> | |
29 | ||
30 | Automatically created from "patches.suse/x86-usb-debug-port-early-console-v4.patch" by xen-port-patches.py | |
31 | ||
32 | --- head-2009-02-02.orig/arch/x86/kernel/early_printk-xen.c 2008-12-15 11:28:15.000000000 +0100 | |
33 | +++ head-2009-02-02/arch/x86/kernel/early_printk-xen.c 2009-02-02 10:17:33.000000000 +0100 | |
34 | @@ -3,10 +3,18 @@ | |
35 | #include <linux/init.h> | |
36 | #include <linux/string.h> | |
37 | #include <linux/screen_info.h> | |
38 | +#include <linux/usb/ch9.h> | |
39 | +#include <linux/pci_regs.h> | |
40 | +#include <linux/pci_ids.h> | |
41 | +#include <linux/errno.h> | |
42 | #include <asm/io.h> | |
43 | #include <asm/processor.h> | |
44 | #include <asm/fcntl.h> | |
45 | #include <asm/setup.h> | |
46 | +#include <asm/pci-direct.h> | |
47 | +#include <asm/pgtable.h> | |
48 | +#include <asm/fixmap.h> | |
49 | +#include <linux/usb/ehci_def.h> | |
50 | ||
51 | /* Simple VGA output */ | |
52 | #define VGABASE (__ISA_IO_base + 0xb8000) | |
53 | @@ -78,6 +86,7 @@ static int early_serial_base = 0x3f8; / | |
54 | static int early_serial_putc(unsigned char ch) | |
55 | { | |
56 | unsigned timeout = 0xffff; | |
57 | + | |
58 | while ((inb(early_serial_base + LSR) & XMTRDY) == 0 && --timeout) | |
59 | cpu_relax(); | |
60 | outb(ch, early_serial_base + TXR); | |
61 | @@ -180,6 +189,721 @@ static struct console early_serial_conso | |
62 | .index = -1, | |
63 | }; | |
64 | ||
65 | +#ifdef CONFIG_EARLY_PRINTK_DBGP | |
66 | + | |
67 | +static struct ehci_caps __iomem *ehci_caps; | |
68 | +static struct ehci_regs __iomem *ehci_regs; | |
69 | +static struct ehci_dbg_port __iomem *ehci_debug; | |
70 | +static unsigned int dbgp_endpoint_out; | |
71 | + | |
72 | +struct ehci_dev { | |
73 | + u32 bus; | |
74 | + u32 slot; | |
75 | + u32 func; | |
76 | +}; | |
77 | + | |
78 | +static struct ehci_dev ehci_dev; | |
79 | + | |
80 | +#define USB_DEBUG_DEVNUM 127 | |
81 | + | |
82 | +#define DBGP_DATA_TOGGLE 0x8800 | |
83 | + | |
84 | +static inline u32 dbgp_pid_update(u32 x, u32 tok) | |
85 | +{ | |
86 | + return ((x ^ DBGP_DATA_TOGGLE) & 0xffff00) | (tok & 0xff); | |
87 | +} | |
88 | + | |
89 | +static inline u32 dbgp_len_update(u32 x, u32 len) | |
90 | +{ | |
91 | + return (x & ~0x0f) | (len & 0x0f); | |
92 | +} | |
93 | + | |
94 | +/* | |
95 | + * USB Packet IDs (PIDs) | |
96 | + */ | |
97 | + | |
98 | +/* token */ | |
99 | +#define USB_PID_OUT 0xe1 | |
100 | +#define USB_PID_IN 0x69 | |
101 | +#define USB_PID_SOF 0xa5 | |
102 | +#define USB_PID_SETUP 0x2d | |
103 | +/* handshake */ | |
104 | +#define USB_PID_ACK 0xd2 | |
105 | +#define USB_PID_NAK 0x5a | |
106 | +#define USB_PID_STALL 0x1e | |
107 | +#define USB_PID_NYET 0x96 | |
108 | +/* data */ | |
109 | +#define USB_PID_DATA0 0xc3 | |
110 | +#define USB_PID_DATA1 0x4b | |
111 | +#define USB_PID_DATA2 0x87 | |
112 | +#define USB_PID_MDATA 0x0f | |
113 | +/* Special */ | |
114 | +#define USB_PID_PREAMBLE 0x3c | |
115 | +#define USB_PID_ERR 0x3c | |
116 | +#define USB_PID_SPLIT 0x78 | |
117 | +#define USB_PID_PING 0xb4 | |
118 | +#define USB_PID_UNDEF_0 0xf0 | |
119 | + | |
120 | +#define USB_PID_DATA_TOGGLE 0x88 | |
121 | +#define DBGP_CLAIM (DBGP_OWNER | DBGP_ENABLED | DBGP_INUSE) | |
122 | + | |
123 | +#define PCI_CAP_ID_EHCI_DEBUG 0xa | |
124 | + | |
125 | +#define HUB_ROOT_RESET_TIME 50 /* times are in msec */ | |
126 | +#define HUB_SHORT_RESET_TIME 10 | |
127 | +#define HUB_LONG_RESET_TIME 200 | |
128 | +#define HUB_RESET_TIMEOUT 500 | |
129 | + | |
130 | +#define DBGP_MAX_PACKET 8 | |
131 | + | |
132 | +static int dbgp_wait_until_complete(void) | |
133 | +{ | |
134 | + u32 ctrl; | |
135 | + int loop = 0x100000; | |
136 | + | |
137 | + do { | |
138 | + ctrl = readl(&ehci_debug->control); | |
139 | + /* Stop when the transaction is finished */ | |
140 | + if (ctrl & DBGP_DONE) | |
141 | + break; | |
142 | + } while (--loop > 0); | |
143 | + | |
144 | + if (!loop) | |
145 | + return -1; | |
146 | + | |
147 | + /* | |
148 | + * Now that we have observed the completed transaction, | |
149 | + * clear the done bit. | |
150 | + */ | |
151 | + writel(ctrl | DBGP_DONE, &ehci_debug->control); | |
152 | + return (ctrl & DBGP_ERROR) ? -DBGP_ERRCODE(ctrl) : DBGP_LEN(ctrl); | |
153 | +} | |
154 | + | |
155 | +static void dbgp_mdelay(int ms) | |
156 | +{ | |
157 | + int i; | |
158 | + | |
159 | + while (ms--) { | |
160 | + for (i = 0; i < 1000; i++) | |
161 | + outb(0x1, 0x80); | |
162 | + } | |
163 | +} | |
164 | + | |
165 | +static void dbgp_breath(void) | |
166 | +{ | |
167 | + /* Sleep to give the debug port a chance to breathe */ | |
168 | +} | |
169 | + | |
170 | +static int dbgp_wait_until_done(unsigned ctrl) | |
171 | +{ | |
172 | + u32 pids, lpid; | |
173 | + int ret; | |
174 | + int loop = 3; | |
175 | + | |
176 | +retry: | |
177 | + writel(ctrl | DBGP_GO, &ehci_debug->control); | |
178 | + ret = dbgp_wait_until_complete(); | |
179 | + pids = readl(&ehci_debug->pids); | |
180 | + lpid = DBGP_PID_GET(pids); | |
181 | + | |
182 | + if (ret < 0) | |
183 | + return ret; | |
184 | + | |
185 | + /* | |
186 | + * If the port is getting full or it has dropped data | |
187 | + * start pacing ourselves, not necessary but it's friendly. | |
188 | + */ | |
189 | + if ((lpid == USB_PID_NAK) || (lpid == USB_PID_NYET)) | |
190 | + dbgp_breath(); | |
191 | + | |
192 | + /* If I get a NACK reissue the transmission */ | |
193 | + if (lpid == USB_PID_NAK) { | |
194 | + if (--loop > 0) | |
195 | + goto retry; | |
196 | + } | |
197 | + | |
198 | + return ret; | |
199 | +} | |
200 | + | |
201 | +static void dbgp_set_data(const void *buf, int size) | |
202 | +{ | |
203 | + const unsigned char *bytes = buf; | |
204 | + u32 lo, hi; | |
205 | + int i; | |
206 | + | |
207 | + lo = hi = 0; | |
208 | + for (i = 0; i < 4 && i < size; i++) | |
209 | + lo |= bytes[i] << (8*i); | |
210 | + for (; i < 8 && i < size; i++) | |
211 | + hi |= bytes[i] << (8*(i - 4)); | |
212 | + writel(lo, &ehci_debug->data03); | |
213 | + writel(hi, &ehci_debug->data47); | |
214 | +} | |
215 | + | |
216 | +static void dbgp_get_data(void *buf, int size) | |
217 | +{ | |
218 | + unsigned char *bytes = buf; | |
219 | + u32 lo, hi; | |
220 | + int i; | |
221 | + | |
222 | + lo = readl(&ehci_debug->data03); | |
223 | + hi = readl(&ehci_debug->data47); | |
224 | + for (i = 0; i < 4 && i < size; i++) | |
225 | + bytes[i] = (lo >> (8*i)) & 0xff; | |
226 | + for (; i < 8 && i < size; i++) | |
227 | + bytes[i] = (hi >> (8*(i - 4))) & 0xff; | |
228 | +} | |
229 | + | |
230 | +static int dbgp_bulk_write(unsigned devnum, unsigned endpoint, | |
231 | + const char *bytes, int size) | |
232 | +{ | |
233 | + u32 pids, addr, ctrl; | |
234 | + int ret; | |
235 | + | |
236 | + if (size > DBGP_MAX_PACKET) | |
237 | + return -1; | |
238 | + | |
239 | + addr = DBGP_EPADDR(devnum, endpoint); | |
240 | + | |
241 | + pids = readl(&ehci_debug->pids); | |
242 | + pids = dbgp_pid_update(pids, USB_PID_OUT); | |
243 | + | |
244 | + ctrl = readl(&ehci_debug->control); | |
245 | + ctrl = dbgp_len_update(ctrl, size); | |
246 | + ctrl |= DBGP_OUT; | |
247 | + ctrl |= DBGP_GO; | |
248 | + | |
249 | + dbgp_set_data(bytes, size); | |
250 | + writel(addr, &ehci_debug->address); | |
251 | + writel(pids, &ehci_debug->pids); | |
252 | + | |
253 | + ret = dbgp_wait_until_done(ctrl); | |
254 | + if (ret < 0) | |
255 | + return ret; | |
256 | + | |
257 | + return ret; | |
258 | +} | |
259 | + | |
260 | +static int dbgp_bulk_read(unsigned devnum, unsigned endpoint, void *data, | |
261 | + int size) | |
262 | +{ | |
263 | + u32 pids, addr, ctrl; | |
264 | + int ret; | |
265 | + | |
266 | + if (size > DBGP_MAX_PACKET) | |
267 | + return -1; | |
268 | + | |
269 | + addr = DBGP_EPADDR(devnum, endpoint); | |
270 | + | |
271 | + pids = readl(&ehci_debug->pids); | |
272 | + pids = dbgp_pid_update(pids, USB_PID_IN); | |
273 | + | |
274 | + ctrl = readl(&ehci_debug->control); | |
275 | + ctrl = dbgp_len_update(ctrl, size); | |
276 | + ctrl &= ~DBGP_OUT; | |
277 | + ctrl |= DBGP_GO; | |
278 | + | |
279 | + writel(addr, &ehci_debug->address); | |
280 | + writel(pids, &ehci_debug->pids); | |
281 | + ret = dbgp_wait_until_done(ctrl); | |
282 | + if (ret < 0) | |
283 | + return ret; | |
284 | + | |
285 | + if (size > ret) | |
286 | + size = ret; | |
287 | + dbgp_get_data(data, size); | |
288 | + return ret; | |
289 | +} | |
290 | + | |
291 | +static int dbgp_control_msg(unsigned devnum, int requesttype, int request, | |
292 | + int value, int index, void *data, int size) | |
293 | +{ | |
294 | + u32 pids, addr, ctrl; | |
295 | + struct usb_ctrlrequest req; | |
296 | + int read; | |
297 | + int ret; | |
298 | + | |
299 | + read = (requesttype & USB_DIR_IN) != 0; | |
300 | + if (size > (read ? DBGP_MAX_PACKET:0)) | |
301 | + return -1; | |
302 | + | |
303 | + /* Compute the control message */ | |
304 | + req.bRequestType = requesttype; | |
305 | + req.bRequest = request; | |
306 | + req.wValue = value; | |
307 | + req.wIndex = index; | |
308 | + req.wLength = size; | |
309 | + | |
310 | + pids = DBGP_PID_SET(USB_PID_DATA0, USB_PID_SETUP); | |
311 | + addr = DBGP_EPADDR(devnum, 0); | |
312 | + | |
313 | + ctrl = readl(&ehci_debug->control); | |
314 | + ctrl = dbgp_len_update(ctrl, sizeof(req)); | |
315 | + ctrl |= DBGP_OUT; | |
316 | + ctrl |= DBGP_GO; | |
317 | + | |
318 | + /* Send the setup message */ | |
319 | + dbgp_set_data(&req, sizeof(req)); | |
320 | + writel(addr, &ehci_debug->address); | |
321 | + writel(pids, &ehci_debug->pids); | |
322 | + ret = dbgp_wait_until_done(ctrl); | |
323 | + if (ret < 0) | |
324 | + return ret; | |
325 | + | |
326 | + /* Read the result */ | |
327 | + return dbgp_bulk_read(devnum, 0, data, size); | |
328 | +} | |
329 | + | |
330 | + | |
331 | +/* Find a PCI capability */ | |
332 | +static u32 __init find_cap(u32 num, u32 slot, u32 func, int cap) | |
333 | +{ | |
334 | + u8 pos; | |
335 | + int bytes; | |
336 | + | |
337 | + if (!(read_pci_config_16(num, slot, func, PCI_STATUS) & | |
338 | + PCI_STATUS_CAP_LIST)) | |
339 | + return 0; | |
340 | + | |
341 | + pos = read_pci_config_byte(num, slot, func, PCI_CAPABILITY_LIST); | |
342 | + for (bytes = 0; bytes < 48 && pos >= 0x40; bytes++) { | |
343 | + u8 id; | |
344 | + | |
345 | + pos &= ~3; | |
346 | + id = read_pci_config_byte(num, slot, func, pos+PCI_CAP_LIST_ID); | |
347 | + if (id == 0xff) | |
348 | + break; | |
349 | + if (id == cap) | |
350 | + return pos; | |
351 | + | |
352 | + pos = read_pci_config_byte(num, slot, func, | |
353 | + pos+PCI_CAP_LIST_NEXT); | |
354 | + } | |
355 | + return 0; | |
356 | +} | |
357 | + | |
358 | +static u32 __init __find_dbgp(u32 bus, u32 slot, u32 func) | |
359 | +{ | |
360 | + u32 class; | |
361 | + | |
362 | + class = read_pci_config(bus, slot, func, PCI_CLASS_REVISION); | |
363 | + if ((class >> 8) != PCI_CLASS_SERIAL_USB_EHCI) | |
364 | + return 0; | |
365 | + | |
366 | + return find_cap(bus, slot, func, PCI_CAP_ID_EHCI_DEBUG); | |
367 | +} | |
368 | + | |
369 | +static u32 __init find_dbgp(int ehci_num, u32 *rbus, u32 *rslot, u32 *rfunc) | |
370 | +{ | |
371 | + u32 bus, slot, func; | |
372 | + | |
373 | + for (bus = 0; bus < 256; bus++) { | |
374 | + for (slot = 0; slot < 32; slot++) { | |
375 | + for (func = 0; func < 8; func++) { | |
376 | + unsigned cap; | |
377 | + | |
378 | + cap = __find_dbgp(bus, slot, func); | |
379 | + | |
380 | + if (!cap) | |
381 | + continue; | |
382 | + if (ehci_num-- != 0) | |
383 | + continue; | |
384 | + *rbus = bus; | |
385 | + *rslot = slot; | |
386 | + *rfunc = func; | |
387 | + return cap; | |
388 | + } | |
389 | + } | |
390 | + } | |
391 | + return 0; | |
392 | +} | |
393 | + | |
394 | +static int ehci_reset_port(int port) | |
395 | +{ | |
396 | + u32 portsc; | |
397 | + u32 delay_time, delay; | |
398 | + int loop; | |
399 | + | |
400 | + /* Reset the usb debug port */ | |
401 | + portsc = readl(&ehci_regs->port_status[port - 1]); | |
402 | + portsc &= ~PORT_PE; | |
403 | + portsc |= PORT_RESET; | |
404 | + writel(portsc, &ehci_regs->port_status[port - 1]); | |
405 | + | |
406 | + delay = HUB_ROOT_RESET_TIME; | |
407 | + for (delay_time = 0; delay_time < HUB_RESET_TIMEOUT; | |
408 | + delay_time += delay) { | |
409 | + dbgp_mdelay(delay); | |
410 | + | |
411 | + portsc = readl(&ehci_regs->port_status[port - 1]); | |
412 | + if (portsc & PORT_RESET) { | |
413 | + /* force reset to complete */ | |
414 | + loop = 2; | |
415 | + writel(portsc & ~(PORT_RWC_BITS | PORT_RESET), | |
416 | + &ehci_regs->port_status[port - 1]); | |
417 | + do { | |
418 | + portsc = readl(&ehci_regs->port_status[port-1]); | |
419 | + } while ((portsc & PORT_RESET) && (--loop > 0)); | |
420 | + } | |
421 | + | |
422 | + /* Device went away? */ | |
423 | + if (!(portsc & PORT_CONNECT)) | |
424 | + return -ENOTCONN; | |
425 | + | |
426 | + /* bomb out completely if something weird happend */ | |
427 | + if ((portsc & PORT_CSC)) | |
428 | + return -EINVAL; | |
429 | + | |
430 | + /* If we've finished resetting, then break out of the loop */ | |
431 | + if (!(portsc & PORT_RESET) && (portsc & PORT_PE)) | |
432 | + return 0; | |
433 | + } | |
434 | + return -EBUSY; | |
435 | +} | |
436 | + | |
437 | +static int ehci_wait_for_port(int port) | |
438 | +{ | |
439 | + u32 status; | |
440 | + int ret, reps; | |
441 | + | |
442 | + for (reps = 0; reps < 3; reps++) { | |
443 | + dbgp_mdelay(100); | |
444 | + status = readl(&ehci_regs->status); | |
445 | + if (status & STS_PCD) { | |
446 | + ret = ehci_reset_port(port); | |
447 | + if (ret == 0) | |
448 | + return 0; | |
449 | + } | |
450 | + } | |
451 | + return -ENOTCONN; | |
452 | +} | |
453 | + | |
454 | +#ifdef DBGP_DEBUG | |
455 | +# define dbgp_printk early_printk | |
456 | +#else | |
457 | +static inline void dbgp_printk(const char *fmt, ...) { } | |
458 | +#endif | |
459 | + | |
460 | +typedef void (*set_debug_port_t)(int port); | |
461 | + | |
462 | +static void default_set_debug_port(int port) | |
463 | +{ | |
464 | +} | |
465 | + | |
466 | +static set_debug_port_t set_debug_port = default_set_debug_port; | |
467 | + | |
468 | +static void nvidia_set_debug_port(int port) | |
469 | +{ | |
470 | + u32 dword; | |
471 | + dword = read_pci_config(ehci_dev.bus, ehci_dev.slot, ehci_dev.func, | |
472 | + 0x74); | |
473 | + dword &= ~(0x0f<<12); | |
474 | + dword |= ((port & 0x0f)<<12); | |
475 | + write_pci_config(ehci_dev.bus, ehci_dev.slot, ehci_dev.func, 0x74, | |
476 | + dword); | |
477 | + dbgp_printk("set debug port to %d\n", port); | |
478 | +} | |
479 | + | |
480 | +static void __init detect_set_debug_port(void) | |
481 | +{ | |
482 | + u32 vendorid; | |
483 | + | |
484 | + vendorid = read_pci_config(ehci_dev.bus, ehci_dev.slot, ehci_dev.func, | |
485 | + 0x00); | |
486 | + | |
487 | + if ((vendorid & 0xffff) == 0x10de) { | |
488 | + dbgp_printk("using nvidia set_debug_port\n"); | |
489 | + set_debug_port = nvidia_set_debug_port; | |
490 | + } | |
491 | +} | |
492 | + | |
493 | +static int __init ehci_setup(void) | |
494 | +{ | |
495 | + struct usb_debug_descriptor dbgp_desc; | |
496 | + u32 cmd, ctrl, status, portsc, hcs_params; | |
497 | + u32 debug_port, new_debug_port = 0, n_ports; | |
498 | + u32 devnum; | |
499 | + int ret, i; | |
500 | + int loop; | |
501 | + int port_map_tried; | |
502 | + int playtimes = 3; | |
503 | + | |
504 | +try_next_time: | |
505 | + port_map_tried = 0; | |
506 | + | |
507 | +try_next_port: | |
508 | + | |
509 | + hcs_params = readl(&ehci_caps->hcs_params); | |
510 | + debug_port = HCS_DEBUG_PORT(hcs_params); | |
511 | + n_ports = HCS_N_PORTS(hcs_params); | |
512 | + | |
513 | + dbgp_printk("debug_port: %d\n", debug_port); | |
514 | + dbgp_printk("n_ports: %d\n", n_ports); | |
515 | + | |
516 | + for (i = 1; i <= n_ports; i++) { | |
517 | + portsc = readl(&ehci_regs->port_status[i-1]); | |
518 | + dbgp_printk("portstatus%d: %08x\n", i, portsc); | |
519 | + } | |
520 | + | |
521 | + if (port_map_tried && (new_debug_port != debug_port)) { | |
522 | + if (--playtimes) { | |
523 | + set_debug_port(new_debug_port); | |
524 | + goto try_next_time; | |
525 | + } | |
526 | + return -1; | |
527 | + } | |
528 | + | |
529 | + loop = 10; | |
530 | + /* Reset the EHCI controller */ | |
531 | + cmd = readl(&ehci_regs->command); | |
532 | + cmd |= CMD_RESET; | |
533 | + writel(cmd, &ehci_regs->command); | |
534 | + do { | |
535 | + cmd = readl(&ehci_regs->command); | |
536 | + } while ((cmd & CMD_RESET) && (--loop > 0)); | |
537 | + | |
538 | + if (!loop) { | |
539 | + dbgp_printk("can not reset ehci\n"); | |
540 | + return -1; | |
541 | + } | |
542 | + dbgp_printk("ehci reset done\n"); | |
543 | + | |
544 | + /* Claim ownership, but do not enable yet */ | |
545 | + ctrl = readl(&ehci_debug->control); | |
546 | + ctrl |= DBGP_OWNER; | |
547 | + ctrl &= ~(DBGP_ENABLED | DBGP_INUSE); | |
548 | + writel(ctrl, &ehci_debug->control); | |
549 | + | |
550 | + /* Start the ehci running */ | |
551 | + cmd = readl(&ehci_regs->command); | |
552 | + cmd &= ~(CMD_LRESET | CMD_IAAD | CMD_PSE | CMD_ASE | CMD_RESET); | |
553 | + cmd |= CMD_RUN; | |
554 | + writel(cmd, &ehci_regs->command); | |
555 | + | |
556 | + /* Ensure everything is routed to the EHCI */ | |
557 | + writel(FLAG_CF, &ehci_regs->configured_flag); | |
558 | + | |
559 | + /* Wait until the controller is no longer halted */ | |
560 | + loop = 10; | |
561 | + do { | |
562 | + status = readl(&ehci_regs->status); | |
563 | + } while ((status & STS_HALT) && (--loop > 0)); | |
564 | + | |
565 | + if (!loop) { | |
566 | + dbgp_printk("ehci can be started\n"); | |
567 | + return -1; | |
568 | + } | |
569 | + dbgp_printk("ehci started\n"); | |
570 | + | |
571 | + /* Wait for a device to show up in the debug port */ | |
572 | + ret = ehci_wait_for_port(debug_port); | |
573 | + if (ret < 0) { | |
574 | + dbgp_printk("No device found in debug port\n"); | |
575 | + goto next_debug_port; | |
576 | + } | |
577 | + dbgp_printk("ehci wait for port done\n"); | |
578 | + | |
579 | + /* Enable the debug port */ | |
580 | + ctrl = readl(&ehci_debug->control); | |
581 | + ctrl |= DBGP_CLAIM; | |
582 | + writel(ctrl, &ehci_debug->control); | |
583 | + ctrl = readl(&ehci_debug->control); | |
584 | + if ((ctrl & DBGP_CLAIM) != DBGP_CLAIM) { | |
585 | + dbgp_printk("No device in debug port\n"); | |
586 | + writel(ctrl & ~DBGP_CLAIM, &ehci_debug->control); | |
587 | + goto err; | |
588 | + } | |
589 | + dbgp_printk("debug ported enabled\n"); | |
590 | + | |
591 | + /* Completely transfer the debug device to the debug controller */ | |
592 | + portsc = readl(&ehci_regs->port_status[debug_port - 1]); | |
593 | + portsc &= ~PORT_PE; | |
594 | + writel(portsc, &ehci_regs->port_status[debug_port - 1]); | |
595 | + | |
596 | + dbgp_mdelay(100); | |
597 | + | |
598 | + /* Find the debug device and make it device number 127 */ | |
599 | + for (devnum = 0; devnum <= 127; devnum++) { | |
600 | + ret = dbgp_control_msg(devnum, | |
601 | + USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE, | |
602 | + USB_REQ_GET_DESCRIPTOR, (USB_DT_DEBUG << 8), 0, | |
603 | + &dbgp_desc, sizeof(dbgp_desc)); | |
604 | + if (ret > 0) | |
605 | + break; | |
606 | + } | |
607 | + if (devnum > 127) { | |
608 | + dbgp_printk("Could not find attached debug device\n"); | |
609 | + goto err; | |
610 | + } | |
611 | + if (ret < 0) { | |
612 | + dbgp_printk("Attached device is not a debug device\n"); | |
613 | + goto err; | |
614 | + } | |
615 | + dbgp_endpoint_out = dbgp_desc.bDebugOutEndpoint; | |
616 | + | |
617 | + /* Move the device to 127 if it isn't already there */ | |
618 | + if (devnum != USB_DEBUG_DEVNUM) { | |
619 | + ret = dbgp_control_msg(devnum, | |
620 | + USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE, | |
621 | + USB_REQ_SET_ADDRESS, USB_DEBUG_DEVNUM, 0, NULL, 0); | |
622 | + if (ret < 0) { | |
623 | + dbgp_printk("Could not move attached device to %d\n", | |
624 | + USB_DEBUG_DEVNUM); | |
625 | + goto err; | |
626 | + } | |
627 | + devnum = USB_DEBUG_DEVNUM; | |
628 | + dbgp_printk("debug device renamed to 127\n"); | |
629 | + } | |
630 | + | |
631 | + /* Enable the debug interface */ | |
632 | + ret = dbgp_control_msg(USB_DEBUG_DEVNUM, | |
633 | + USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE, | |
634 | + USB_REQ_SET_FEATURE, USB_DEVICE_DEBUG_MODE, 0, NULL, 0); | |
635 | + if (ret < 0) { | |
636 | + dbgp_printk(" Could not enable the debug device\n"); | |
637 | + goto err; | |
638 | + } | |
639 | + dbgp_printk("debug interface enabled\n"); | |
640 | + | |
641 | + /* Perform a small write to get the even/odd data state in sync | |
642 | + */ | |
643 | + ret = dbgp_bulk_write(USB_DEBUG_DEVNUM, dbgp_endpoint_out, " ", 1); | |
644 | + if (ret < 0) { | |
645 | + dbgp_printk("dbgp_bulk_write failed: %d\n", ret); | |
646 | + goto err; | |
647 | + } | |
648 | + dbgp_printk("small write doned\n"); | |
649 | + | |
650 | + return 0; | |
651 | +err: | |
652 | + /* Things didn't work so remove my claim */ | |
653 | + ctrl = readl(&ehci_debug->control); | |
654 | + ctrl &= ~(DBGP_CLAIM | DBGP_OUT); | |
655 | + writel(ctrl, &ehci_debug->control); | |
656 | + return -1; | |
657 | + | |
658 | +next_debug_port: | |
659 | + port_map_tried |= (1<<(debug_port - 1)); | |
660 | + new_debug_port = ((debug_port-1+1)%n_ports) + 1; | |
661 | + if (port_map_tried != ((1<<n_ports) - 1)) { | |
662 | + set_debug_port(new_debug_port); | |
663 | + goto try_next_port; | |
664 | + } | |
665 | + if (--playtimes) { | |
666 | + set_debug_port(new_debug_port); | |
667 | + goto try_next_time; | |
668 | + } | |
669 | + | |
670 | + return -1; | |
671 | +} | |
672 | + | |
673 | +static int __init early_dbgp_init(char *s) | |
674 | +{ | |
675 | + u32 debug_port, bar, offset; | |
676 | + u32 bus, slot, func, cap; | |
677 | + void __iomem *ehci_bar; | |
678 | + u32 dbgp_num; | |
679 | + u32 bar_val; | |
680 | + char *e; | |
681 | + int ret; | |
682 | + u8 byte; | |
683 | + | |
684 | + if (!early_pci_allowed()) | |
685 | + return -1; | |
686 | + | |
687 | + dbgp_num = 0; | |
688 | + if (*s) | |
689 | + dbgp_num = simple_strtoul(s, &e, 10); | |
690 | + dbgp_printk("dbgp_num: %d\n", dbgp_num); | |
691 | + | |
692 | + cap = find_dbgp(dbgp_num, &bus, &slot, &func); | |
693 | + if (!cap) | |
694 | + return -1; | |
695 | + | |
696 | + dbgp_printk("Found EHCI debug port on %02x:%02x.%1x\n", bus, slot, | |
697 | + func); | |
698 | + | |
699 | + debug_port = read_pci_config(bus, slot, func, cap); | |
700 | + bar = (debug_port >> 29) & 0x7; | |
701 | + bar = (bar * 4) + 0xc; | |
702 | + offset = (debug_port >> 16) & 0xfff; | |
703 | + dbgp_printk("bar: %02x offset: %03x\n", bar, offset); | |
704 | + if (bar != PCI_BASE_ADDRESS_0) { | |
705 | + dbgp_printk("only debug ports on bar 1 handled.\n"); | |
706 | + | |
707 | + return -1; | |
708 | + } | |
709 | + | |
710 | + bar_val = read_pci_config(bus, slot, func, PCI_BASE_ADDRESS_0); | |
711 | + dbgp_printk("bar_val: %02x offset: %03x\n", bar_val, offset); | |
712 | + if (bar_val & ~PCI_BASE_ADDRESS_MEM_MASK) { | |
713 | + dbgp_printk("only simple 32bit mmio bars supported\n"); | |
714 | + | |
715 | + return -1; | |
716 | + } | |
717 | + | |
718 | + /* double check if the mem space is enabled */ | |
719 | + byte = read_pci_config_byte(bus, slot, func, 0x04); | |
720 | + if (!(byte & 0x2)) { | |
721 | + byte |= 0x02; | |
722 | + write_pci_config_byte(bus, slot, func, 0x04, byte); | |
723 | + dbgp_printk("mmio for ehci enabled\n"); | |
724 | + } | |
725 | + | |
726 | + /* | |
727 | + * FIXME I don't have the bar size so just guess PAGE_SIZE is more | |
728 | + * than enough. 1K is the biggest I have seen. | |
729 | + */ | |
730 | + set_fixmap_nocache(FIX_DBGP_BASE, bar_val & PAGE_MASK); | |
731 | + ehci_bar = (void __iomem *)__fix_to_virt(FIX_DBGP_BASE); | |
732 | + ehci_bar += bar_val & ~PAGE_MASK; | |
733 | + dbgp_printk("ehci_bar: %p\n", ehci_bar); | |
734 | + | |
735 | + ehci_caps = ehci_bar; | |
736 | + ehci_regs = ehci_bar + HC_LENGTH(readl(&ehci_caps->hc_capbase)); | |
737 | + ehci_debug = ehci_bar + offset; | |
738 | + ehci_dev.bus = bus; | |
739 | + ehci_dev.slot = slot; | |
740 | + ehci_dev.func = func; | |
741 | + | |
742 | + detect_set_debug_port(); | |
743 | + | |
744 | + ret = ehci_setup(); | |
745 | + if (ret < 0) { | |
746 | + dbgp_printk("ehci_setup failed\n"); | |
747 | + ehci_debug = 0; | |
748 | + | |
749 | + return -1; | |
750 | + } | |
751 | + | |
752 | + return 0; | |
753 | +} | |
754 | + | |
755 | +static void early_dbgp_write(struct console *con, const char *str, u32 n) | |
756 | +{ | |
757 | + int chunk, ret; | |
758 | + | |
759 | + if (!ehci_debug) | |
760 | + return; | |
761 | + while (n > 0) { | |
762 | + chunk = n; | |
763 | + if (chunk > DBGP_MAX_PACKET) | |
764 | + chunk = DBGP_MAX_PACKET; | |
765 | + ret = dbgp_bulk_write(USB_DEBUG_DEVNUM, | |
766 | + dbgp_endpoint_out, str, chunk); | |
767 | + str += chunk; | |
768 | + n -= chunk; | |
769 | + } | |
770 | +} | |
771 | + | |
772 | +static struct console early_dbgp_console = { | |
773 | + .name = "earlydbg", | |
774 | + .write = early_dbgp_write, | |
775 | + .flags = CON_PRINTBUFFER, | |
776 | + .index = -1, | |
777 | +}; | |
778 | +#endif | |
779 | + | |
780 | /* Console interface to a host file on AMD's SimNow! */ | |
781 | ||
782 | static int simnow_fd; | |
783 | @@ -194,6 +918,7 @@ enum { | |
784 | static noinline long simnow(long cmd, long a, long b, long c) | |
785 | { | |
786 | long ret; | |
787 | + | |
788 | asm volatile("cpuid" : | |
789 | "=a" (ret) : | |
790 | "b" (a), "c" (b), "d" (c), "0" (MAGIC1), "D" (cmd + MAGIC2)); | |
791 | @@ -203,6 +928,7 @@ static noinline long simnow(long cmd, lo | |
792 | static void __init simnow_init(char *str) | |
793 | { | |
794 | char *fn = "klog"; | |
795 | + | |
796 | if (*str == '=') | |
797 | fn = ++str; | |
798 | /* error ignored */ | |
799 | @@ -237,10 +963,11 @@ asmlinkage void early_printk(const char | |
800 | va_end(ap); | |
801 | } | |
802 | ||
803 | -static int __initdata keep_early; | |
804 | ||
805 | static int __init setup_early_printk(char *buf) | |
806 | { | |
807 | + int keep_early; | |
808 | + | |
809 | if (!buf) | |
810 | return 0; | |
811 | ||
812 | @@ -248,8 +975,7 @@ static int __init setup_early_printk(cha | |
813 | return 0; | |
814 | early_console_initialized = 1; | |
815 | ||
816 | - if (strstr(buf, "keep")) | |
817 | - keep_early = 1; | |
818 | + keep_early = (strstr(buf, "keep") != NULL); | |
819 | ||
820 | if (!strncmp(buf, "serial", 6)) { | |
821 | early_serial_init(buf + 6); | |
822 | @@ -269,6 +995,17 @@ static int __init setup_early_printk(cha | |
823 | simnow_init(buf + 6); | |
824 | early_console = &simnow_console; | |
825 | keep_early = 1; | |
826 | +#ifdef CONFIG_EARLY_PRINTK_DBGP | |
827 | + } else if (!strncmp(buf, "dbgp", 4)) { | |
828 | + if (early_dbgp_init(buf+4) < 0) | |
829 | + return 0; | |
830 | + early_console = &early_dbgp_console; | |
831 | + /* | |
832 | + * usb subsys will reset ehci controller, so don't keep | |
833 | + * that early console | |
834 | + */ | |
835 | + keep_early = 0; | |
836 | +#endif | |
837 | #ifdef CONFIG_XEN | |
838 | } else if (!strncmp(buf, "xen", 3)) { | |
839 | early_console = &xenboot_console; | |
840 | @@ -282,4 +1019,23 @@ static int __init setup_early_printk(cha | |
841 | register_console(early_console); | |
842 | return 0; | |
843 | } | |
844 | + | |
845 | +void __init enable_debug_console(char *buf) | |
846 | +{ | |
847 | +#ifdef DBGP_DEBUG | |
848 | + struct console *old_early_console = NULL; | |
849 | + | |
850 | + if (early_console_initialized && early_console) { | |
851 | + old_early_console = early_console; | |
852 | + unregister_console(early_console); | |
853 | + early_console_initialized = 0; | |
854 | + } | |
855 | + | |
856 | + setup_early_printk(buf); | |
857 | + | |
858 | + if (early_console == old_early_console && old_early_console) | |
859 | + register_console(old_early_console); | |
860 | +#endif | |
861 | +} | |
862 | + | |
863 | early_param("earlyprintk", setup_early_printk); |