LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
* RE: [LinuxBIOS] #57: libusb host program for PLX NET20DC debug device
@ 2006-12-01 18:55 Lu, Yinghai
  2006-12-01 19:19 ` Greg KH
  0 siblings, 1 reply; 29+ messages in thread
From: Lu, Yinghai @ 2006-12-01 18:55 UTC (permalink / raw)
  To: Greg KH
  Cc: Stefan Reinauer, Peter Stuge, Eric W. Biederman, linuxbios, linux-kernel

-----Original Message-----
From: Greg KH [mailto:gregkh@suse.de] 

>I can do that in about 15 minutes if you give me the device ids for the
>usb debug device that you wish to have.

>Or you can also use the generic usb-serial driver today just fine with
>no modification.  Have you had a problem with using that option?

We are talking about using USB debug device/EHCI debug port in LinuxBIOS
in legacy free PC.
Because one AM2+MCP55 MB doesn't have serial port.

I guess Eric is working on USB debug device/EHCI debug port for
earlyprintk or printk.

So we need one client program on host side. So it would great if we
could use current USB stack for 
the clients on system even without debug port.

I'm getting one USB debug device cable, and will test generic usb_serial
driver.

Thanks

YH




^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [LinuxBIOS] #57: libusb host program for PLX NET20DC debug device
  2006-12-01 18:55 [LinuxBIOS] #57: libusb host program for PLX NET20DC debug device Lu, Yinghai
@ 2006-12-01 19:19 ` Greg KH
  2006-12-01 20:42   ` Peter Stuge
                     ` (2 more replies)
  0 siblings, 3 replies; 29+ messages in thread
From: Greg KH @ 2006-12-01 19:19 UTC (permalink / raw)
  To: Lu, Yinghai
  Cc: Stefan Reinauer, Peter Stuge, Eric W. Biederman, linuxbios, linux-kernel

On Fri, Dec 01, 2006 at 10:55:48AM -0800, Lu, Yinghai wrote:
> -----Original Message-----
> From: Greg KH [mailto:gregkh@suse.de] 
> 
> >I can do that in about 15 minutes if you give me the device ids for the
> >usb debug device that you wish to have.
> 
> >Or you can also use the generic usb-serial driver today just fine with
> >no modification.  Have you had a problem with using that option?
> 
> We are talking about using USB debug device/EHCI debug port in LinuxBIOS
> in legacy free PC.
> Because one AM2+MCP55 MB doesn't have serial port.
> 
> I guess Eric is working on USB debug device/EHCI debug port for
> earlyprintk or printk.

Well, earlyprintk will not work, as you need PCI up and running.

And I have some code that barely works for this already, perhaps Eric
and I should work together on this :)

> So we need one client program on host side. So it would great if we
> could use current USB stack for 
> the clients on system even without debug port.

Yes, that will work just fine today using the usb-serial generic driver.
I'll knock up a "real" driver for the device later today and send it to
Linus, as it's trivial to do so, and will make it simpler than using the
module parameters.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [LinuxBIOS] #57: libusb host program for PLX NET20DC debug device
  2006-12-01 19:19 ` Greg KH
@ 2006-12-01 20:42   ` Peter Stuge
  2006-12-01 21:15     ` Eric W. Biederman
  2006-12-01 23:13   ` Eric W. Biederman
  2006-12-03 15:49   ` Eric W. Biederman
  2 siblings, 1 reply; 29+ messages in thread
From: Peter Stuge @ 2006-12-01 20:42 UTC (permalink / raw)
  To: Greg KH
  Cc: Lu, Yinghai, Stefan Reinauer, Eric W. Biederman, linuxbios, linux-kernel

On Fri, Dec 01, 2006 at 11:19:16AM -0800, Greg KH wrote:
> Well, earlyprintk will not work, as you need PCI up and running.

Not all of it though. LinuxBIOS will probably do just enough PCI
setup to talk to the EHCI controller and use the debug port _very_
soon after power on.


> And I have some code that barely works for this already, perhaps
> Eric and I should work together on this :)

I would be interested in having a look at any code for it too.


> Yes, that will work just fine today using the usb-serial generic
> driver.

Ugh. I did not know it was that generic. The irony is that I always
ask other libusb users to check the kernel drivers to see if they
really need to write a libusb app.


> I'll knock up a "real" driver for the device later today and send
> it to Linus, as it's trivial to do so, and will make it simpler
> than using the module parameters.

Awesome. Thanks!


//Peter

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [LinuxBIOS] #57: libusb host program for PLX NET20DC debug device
  2006-12-01 20:42   ` Peter Stuge
@ 2006-12-01 21:15     ` Eric W. Biederman
  2006-12-01 21:46       ` Peter Stuge
  0 siblings, 1 reply; 29+ messages in thread
From: Eric W. Biederman @ 2006-12-01 21:15 UTC (permalink / raw)
  To: Greg KH, Andi Kleen; +Cc: Lu, Yinghai, Stefan Reinauer, linuxbios, linux-kernel

Peter Stuge <stuge-linuxbios@cdy.org> writes:

> On Fri, Dec 01, 2006 at 11:19:16AM -0800, Greg KH wrote:
>> Well, earlyprintk will not work, as you need PCI up and running.
>
> Not all of it though. LinuxBIOS will probably do just enough PCI
> setup to talk to the EHCI controller and use the debug port _very_
> soon after power on.

Right.  For LinuxBIOS not a problem for earlyprintk in the kernel
somethings might need to be refactored.  The challenge in the kernel
is we don't know at build to how to do a pci_read_config...

The other hard part early in the kernel is the fact that the
bar is memory mapped I/O.  Which means it will need to get mapped
into the kernels page tables.

>> And I have some code that barely works for this already, perhaps
>> Eric and I should work together on this :)
>
> I would be interested in having a look at any code for it too.

Sure, I will send it out shortly.  I currently have a working
user space libusb thing (easy, but useful for my debug) and 
a rude read/write to the bar from user space program that
allowed me to debug the worst of the state machine from user
space.  I don't think I have the state setup logic correct yet
but that is minor in comparison.

I really wish the EHCI spec had made that stupid interface 16 bytes
instead of 8 or had a way to chain multiple access together.  The
we could have used a normal usb cable.  As it is most descriptors
are 1 byte to big to read.

>> Yes, that will work just fine today using the usb-serial generic
>> driver.
>
> Ugh. I did not know it was that generic. The irony is that I always
> ask other libusb users to check the kernel drivers to see if they
> really need to write a libusb app.
>
>
>> I'll knock up a "real" driver for the device later today and send
>> it to Linus, as it's trivial to do so, and will make it simpler
>> than using the module parameters.
>
> Awesome. Thanks!

Yep. It looks like it sufficient generic.  The Maximum packet size
appears to be reported correctly for writes which is the tidbit
I was worried about but otherwise it is just a pair of bulk transfer
endpoints.

Eric

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [LinuxBIOS] #57: libusb host program for PLX NET20DC debug device
  2006-12-01 21:15     ` Eric W. Biederman
@ 2006-12-01 21:46       ` Peter Stuge
  2006-12-01 23:02         ` Eric W. Biederman
  0 siblings, 1 reply; 29+ messages in thread
From: Peter Stuge @ 2006-12-01 21:46 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: Greg KH, Andi Kleen, Stefan Reinauer, linuxbios, linux-kernel,
	Lu, Yinghai

On Fri, Dec 01, 2006 at 02:15:24PM -0700, Eric W. Biederman wrote:
> Right.  For LinuxBIOS not a problem for earlyprintk in the kernel
> somethings might need to be refactored.  The challenge in the
> kernel is we don't know at build to how to do a pci_read_config...
> 
> The other hard part early in the kernel is the fact that the
> bar is memory mapped I/O.  Which means it will need to get mapped
> into the kernels page tables.

I see.


> >> And I have some code that barely works for this already, perhaps
> >> Eric and I should work together on this :)
> >
> > I would be interested in having a look at any code for it too.
> 
> Sure, I will send it out shortly.  I currently have a working
> user space libusb thing (easy, but useful for my debug)

Hm - for driving which end?


> and a rude read/write to the bar from user space program that

How does that work? /dev/{port,mem}?


> allowed me to debug the worst of the state machine from user
> space.  I don't think I have the state setup logic correct yet
> but that is minor in comparison.
> 
> I really wish the EHCI spec had made that stupid interface 16 bytes
> instead of 8 or had a way to chain multiple access together.  The
> we could have used a normal usb cable.  As it is most descriptors
> are 1 byte to big to read.

Which descriptors are you reading?

The debug port isn't really supposed to be used with anything but a
debug device - which can't be enumerated normally anyway.


//Peter

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [LinuxBIOS] #57: libusb host program for PLX NET20DC debug device
  2006-12-01 21:46       ` Peter Stuge
@ 2006-12-01 23:02         ` Eric W. Biederman
  2006-12-03 17:00           ` Peter Stuge
  0 siblings, 1 reply; 29+ messages in thread
From: Eric W. Biederman @ 2006-12-01 23:02 UTC (permalink / raw)
  To: Peter Stuge
  Cc: Greg KH, Andi Kleen, Stefan Reinauer, linuxbios, linux-kernel,
	Lu, Yinghai

Peter Stuge <stuge-linuxbios@cdy.org> writes:

> On Fri, Dec 01, 2006 at 02:15:24PM -0700, Eric W. Biederman wrote:
>> Right.  For LinuxBIOS not a problem for earlyprintk in the kernel
>> somethings might need to be refactored.  The challenge in the
>> kernel is we don't know at build to how to do a pci_read_config...
>> 
>> The other hard part early in the kernel is the fact that the
>> bar is memory mapped I/O.  Which means it will need to get mapped
>> into the kernels page tables.
>
> I see.
>
>
>> >> And I have some code that barely works for this already, perhaps
>> >> Eric and I should work together on this :)
>> >
>> > I would be interested in having a look at any code for it too.
>> 
>> Sure, I will send it out shortly.  I currently have a working
>> user space libusb thing (easy, but useful for my debug)
>
> Hm - for driving which end?

Either.  The specific device we are talking about doesn't care.

>> and a rude read/write to the bar from user space program that
>
> How does that work? /dev/{port,mem}?

mmap /dev/mem.

>> allowed me to debug the worst of the state machine from user
>> space.  I don't think I have the state setup logic correct yet
>> but that is minor in comparison.
>> 
>> I really wish the EHCI spec had made that stupid interface 16 bytes
>> instead of 8 or had a way to chain multiple access together.  The
>> we could have used a normal usb cable.  As it is most descriptors
>> are 1 byte too big to read.
>
> Which descriptors are you reading?

Minor.  I was just wishing for less magic in this process, which
would make these kinds of devices much more available.

> The debug port isn't really supposed to be used with anything but a
> debug device - which can't be enumerated normally anyway.

It depends.  If you have a debug cable with magic ends and a hardcoded
address of 127 the normal enumeration doesn't work.  I don't think
anyone actually makes one of those.  Debug devices are also allowed to
be normal devices that just support the debug descriptor.  Which
is what I'm working with.

Eric


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [LinuxBIOS] #57: libusb host program for PLX NET20DC debug device
  2006-12-01 19:19 ` Greg KH
  2006-12-01 20:42   ` Peter Stuge
@ 2006-12-01 23:13   ` Eric W. Biederman
  2006-12-03 15:49   ` Eric W. Biederman
  2 siblings, 0 replies; 29+ messages in thread
From: Eric W. Biederman @ 2006-12-01 23:13 UTC (permalink / raw)
  To: Greg KH
  Cc: Lu, Yinghai, Stefan Reinauer, Peter Stuge, linuxbios,
	linux-kernel, Andi Kleen

[-- Attachment #1: Type: text/plain, Size: 2345 bytes --]

Greg KH <gregkh@suse.de> writes:

> On Fri, Dec 01, 2006 at 10:55:48AM -0800, Lu, Yinghai wrote:
>> -----Original Message-----
>> From: Greg KH [mailto:gregkh@suse.de] 
>> 
>> >I can do that in about 15 minutes if you give me the device ids for the
>> >usb debug device that you wish to have.
>> 
>> >Or you can also use the generic usb-serial driver today just fine with
>> >no modification.  Have you had a problem with using that option?
>> 
>> We are talking about using USB debug device/EHCI debug port in LinuxBIOS
>> in legacy free PC.
>> Because one AM2+MCP55 MB doesn't have serial port.
>> 
>> I guess Eric is working on USB debug device/EHCI debug port for
>> earlyprintk or printk.
>
> Well, earlyprintk will not work, as you need PCI up and running.
>
> And I have some code that barely works for this already, perhaps Eric
> and I should work together on this :)

I'd love to work with someone on this.  I'm cc'ing Andi Kleen because
he asked me where we had gotten on this the other day.

One big thing we need is a way to tell if you have the
system booted if your device is plugged into the usb port that
connects to the usb debug port.  Figuring out which usb port
you really have to plug into is still trying and error but at
least being able to tell without having to try the code is good.

So here is my mostly somewhat working code.  I don't understand
what you have todo if you want to reset the device and then
find the device so this code currently only works if you have
ehci_hcd already loaded. 

I am avoiding the pci bit simply by having someone pass me the
hard coded numbers...

I think I can get it down to a single base address if I don't
print debugging of which port you are plugged into, or try and
debug the state out of reset.

usbtest.c is my little libusb client program.  It's useful
for exploring things.

usbdebug_direct.c is roughly a driver living in user space
so I can debug the hard bits of the logic.  Not a good production
technique but great for prototyping.  It has all of the basic
primitives needed to actually use the ehci debug port.

The next big thing for me I guess is to modify a kernel and see
what state the usb ports are in when I am booting and how much
of the reset logic I need to understand to make this work.
Greg I expect you understand that a little better than I do.

Eric


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: usbtest.c --]
[-- Type: text/x-csrc, Size: 7104 bytes --]

/*
 * Copyright (C) 2006 Eric Biederman (ebiederm@xmission.com)
 *
 *	This program is free software; you can redistribute it and/or
 *	modify it under the terms of the GNU General Public License version
 *	2 as published by the Free Software Foundation.
 *
 *      gcc -Wall -o ./usbtest ./usbtest.c -lusb
 */
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <usb.h>

#define DEBUG_DEVICE_MAX 8

#ifndef USB_DT_DEBUG
#define USB_DT_DEBUG	10
#endif
#ifndef USB_FT_DEBUG_MODE
#define USB_FT_DEBUG_MODE	6
#endif 
#define CTRL_TIMEOUT	(5*1000)	/* milliseconds */
#define WRITE_TIMEOUT	(60*1000*1000)	/* 1 minute */

struct usb_debug_descriptor {
	uint8_t	bLength;
	uint8_t bDescriptorType;
	uint8_t bDebugInEndpoint;
	uint8_t bDebugOutEndpoint;
} __attribute__ ((packed));


static void die(char *fmt, ...)
{
	va_list ap;
	va_start(ap, fmt);
	vfprintf(stderr, fmt, ap);
	va_end(ap);
	fflush(stderr);
	fflush(stdout);
	exit(1);
}


static struct usb_device *next_debug_device(struct usb_device *dev,
	struct usb_debug_descriptor *debug)
{
	struct usb_bus *bus;
	if (dev) {
		bus = dev->bus;
		goto next;
	}
	for (bus = usb_busses; bus; bus = bus->next) {
		for (dev = bus->devices; dev; dev = dev->next) {
			struct usb_dev_handle *handle;
			int ret;
#if 1
			printf("%02x:%02x\n",
				dev->descriptor.idVendor,
				dev->descriptor.idProduct);
#endif
			handle = usb_open(dev);
			if (!handle)
				goto next;
			ret = usb_get_descriptor(handle, USB_DT_DEBUG, 0,
				debug, sizeof(*debug));
			usb_close(handle);
#if 1
			printf("ret: %d\n", ret);
#endif
			if (ret == sizeof(*debug))
				return dev;
next:
			;
		}
	}
	return NULL;
}

static int usb_set_debug_mode(usb_dev_handle *handle)
{
	return usb_control_msg(handle, USB_TYPE_STANDARD | USB_RECIP_DEVICE,
		USB_REQ_SET_FEATURE, USB_FT_DEBUG_MODE, 0, NULL, 0,
		CTRL_TIMEOUT);
		
}

static int usb_unconfigure(usb_dev_handle *handle)
{
	return usb_control_msg(handle, USB_TYPE_STANDARD | USB_RECIP_DEVICE,
		USB_REQ_SET_CONFIGURATION, 0, 0, NULL, 0,
		CTRL_TIMEOUT);
}


static int usb_debug_read(struct usb_device *dev,
				struct usb_debug_descriptor *debug)
{
	struct usb_dev_handle *handle;
	char buf[DEBUG_DEVICE_MAX];
	int iface, i, j;
	int ret = -1;

	/* Find the interface to claim! */
	iface = -1;
	for (i = 0; i < dev->config->interface->num_altsetting; i++) {
		struct usb_interface_descriptor *face;
		face = &dev->config->interface->altsetting[i];
		for (j = 0; j < face->bNumEndpoints; j++) {
			if (face->endpoint[j].bEndpointAddress == 
			    debug->bDebugInEndpoint) {
				iface = face->bInterfaceNumber;
				printf("wMaxPacketSize: %u iface: %d\n",
					face->endpoint[j].bEndpointAddress,
					iface);
				goto found_iface;
			}
		}
	}
	goto out;
found_iface:

	handle = usb_open(dev);
	if (!handle)
		goto out;
	if ((ret = usb_claim_interface(handle, iface)) < 0)
		goto out_close;
	if ((ret = usb_set_debug_mode(handle)) < 0)
		goto out_release;
	for (;;) {
		ret = usb_bulk_read(handle, debug->bDebugInEndpoint,
			buf, sizeof(buf), 1000000);
		if (ret < 0)
			goto out_release;
		printf("%d:%*.*s", ret, ret, ret, buf);
	}
out_release:
	usb_release_interface(handle, iface);
out_close:	
	usb_close(handle);
out:
	return ret;
}


static int usb_debug_write(struct usb_device *dev,
				struct usb_debug_descriptor *debug)
{
	struct usb_dev_handle *handle;
	char buf[DEBUG_DEVICE_MAX];
	int iface, i, j;
	int ret;

	ret = -1;
	/* Find the interface to claim! */
	iface = -1;
	for (i = 0; i < dev->config->interface->num_altsetting; i++) {
		struct usb_interface_descriptor *face;
		face = &dev->config->interface->altsetting[i];
		for (j = 0; j < face->bNumEndpoints; j++) {
			if (face->endpoint[j].bEndpointAddress == 
			    debug->bDebugOutEndpoint) {
				iface = face->bInterfaceNumber;
				printf("wMaxPacketSize: %u iface: %d\n",
					face->endpoint[j].bEndpointAddress,
					iface);
				goto found_iface;
			}
		}
	}
	goto out;
found_iface:
	handle = usb_open(dev);
	if (!handle)
		goto out;
	if ((ret = usb_claim_interface(handle, iface)) < 0)
		goto out_close;
	if ((ret = usb_set_debug_mode(handle)) < 0)
		goto out_release;
	for (;;) {
		if ((ret = read(STDIN_FILENO, buf, sizeof(buf))) <= 0)
			goto out_shutdown;

#if 1
		printf("%d:%*.*s", ret, ret, ret, buf);
#endif
		ret = usb_bulk_write(handle, debug->bDebugOutEndpoint,
			buf, ret, WRITE_TIMEOUT);
#if 1
		printf("usb_bulk_write: %d\n", ret);
#endif
		if (ret < 0)
			goto out_shutdown;
	}
out_shutdown:
	usb_unconfigure(handle);
out_release:
	usb_release_interface(handle, iface);
out_close:	
	usb_close(handle);
out:
	return ret;
}

enum debug_op {
	DEBUG_LIST = 0,
	DEBUG_REDIR = 1,
	DEBUG_READ  = 2,
	DEBUG_WRITE = 3,
};
int main(int argc, char **argv)
{
	struct usb_device *dev;
	struct usb_debug_descriptor debug_desc;
	int i;
	int wanted_bus, wanted_dev;
	int wanted_vendor, wanted_product;
	enum debug_op op;

	op = DEBUG_REDIR;
	wanted_bus = wanted_dev = -1;
	wanted_vendor = wanted_product = -1;
	for (i = 1; i < argc; i++) {
		if (strcmp(argv[i], "-s") == 0) {
			char *colon;
			i++;
			if (i >= argc)
				die("missing argument");
			colon = strchr(argv[i], ':');
			if (!colon)
				wanted_dev = strtoul(argv[i], NULL, 10);
			else {
				wanted_bus = strtoul(argv[i], NULL, 10);
				wanted_dev = strtoul(colon + 1, NULL, 10);
			}
		} 
		else if (strcmp(argv[i], "-d") == 0) {
			char *colon;
			i++;
			if (i >= argc)
				die("missing argument");
			wanted_vendor = strtoul(argv[i], NULL, 16);
			if (colon)
				wanted_product = strtoul(colon + 1, NULL, 16);
		}
		else if (strcmp(argv[i], "-l") == 0) {
			op = DEBUG_LIST;
		}
		else if (strcmp(argv[i], "-r") == 0) {
			op = DEBUG_READ;
		}
		else if (strcmp(argv[i], "-w") == 0) {
			op = DEBUG_WRITE;
		}
		else if (strcmp(argv[i], "-rw") == 0) {
			op = DEBUG_REDIR;
		}
		else {
			die("Unknown argument: %s\n", argv[i]);
		}
#if 0
		if (strcmp(argv[i], "-d") == 0)
			break;
#endif
	}

	
	usb_init();
	usb_find_busses();
	usb_find_devices();
	
	dev = next_debug_device(NULL, &debug_desc);
	for (; dev; dev = next_debug_device(dev, &debug_desc)) {
		int busnum;
		busnum = strtol(dev->bus->dirname, NULL, 10);
		if ((wanted_bus != -1) && (busnum != wanted_bus))
			continue;
		if ((wanted_dev != -1) && (dev->devnum != wanted_dev))
			continue;
		if ((wanted_vendor != -1) && 
		    (dev->descriptor.idVendor != wanted_vendor))
			continue;
		if ((wanted_product != -1) && 
		    (dev->descriptor.idProduct != wanted_product))
			continue;
		if (op != DEBUG_LIST)
			goto found;
		printf("%d.%d %04x:%04x\n",
			busnum, dev->devnum,
			dev->descriptor.idVendor,
			dev->descriptor.idProduct);
	}
	if (op == DEBUG_LIST)
		return 0;
	die("No debug devices found\n");
found:	
	printf("Found one!\n");
	printf("desc: %02x %02x %02x %02x\n",
		debug_desc.bLength,
		debug_desc.bDescriptorType,
		debug_desc.bDebugInEndpoint,
		debug_desc.bDebugOutEndpoint);


	switch(op) {
	case DEBUG_READ:
		usb_debug_read(dev, &debug_desc);
		break;
	case DEBUG_WRITE:
		usb_debug_write(dev, &debug_desc);
		break;
	default:
		die("Unknown operation\n");
	}
	return 0;
}

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: usbdebug_direct.c --]
[-- Type: text/x-csrc, Size: 17393 bytes --]

/*
 * Copyright (C) 2006 Eric Biederman (ebiederm@xmission.com)
 *
 *	This program is free software; you can redistribute it and/or
 *	modify it under the terms of the GNU General Public License version
 *	2 as published by the Free Software Foundation.
 *
 *      gcc -Wall -o ./usbdebug_direct ./usbdebug_direct.c
 */

#define _LARGEFILE_SOURCE
#define _FILE_OFFSET_BITS 64
#define _POSIC_C_SOURCE 199309
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <time.h>

static void die(char *fmt, ...)
{
	va_list ap;
	va_start(ap, fmt);
	vfprintf(stderr, fmt, ap);
	va_end(ap);
	fflush(stderr);
	fflush(stdout);
	exit(1);
}


static inline uint8_t readb(const volatile void  *addr)
{
	return *(volatile uint8_t *)addr;
}
static inline uint16_t readw(const volatile void  *addr)
{
	return *(volatile uint16_t *)addr;
}
static inline uint32_t readl(const volatile void  *addr)
{
	return *(volatile uint32_t *)addr;
}
static inline void writel(uint32_t b, volatile void  *addr)
{
	*(volatile uint32_t *)addr = b;
}
static inline void writeb(uint8_t b, volatile void  *addr)
{
	*(volatile uint8_t *)addr = b;
}
static inline void writew(uint16_t b, volatile void  *addr)
{
	*(volatile uint16_t *)addr = b;
}


//#define EHCI_BAR 0xbfce0000
#define EHCI_BAR_BYTES 4096
//#define EHCI_DEBUG_OFFSET 0x98
#define PAGE_SIZE 4096UL

static void *ehci_base, *ehci_op_base, *ehci_debug_base;

/* Off of ehci_base */
#define EHCI_CAPLENGTH		0x00
#define EHCI_HCIVERSION		0x02
#define EHCI_HCSPARAMS		0x04
#define EHCI_HCCPARAMS		0x08
#define EHCI_HCSP_PORTROUTE	0x0c

/* Off of ehci_op_base */
#define EHCI_USBCMD		0x00
#define  EHCI_USBCMD_RUN		(1 << 0)
#define EHCI_USBSTS		0x04
#define  EHCI_USBSTS_HCHALTED		(1 << 12)
#define EHCI_USBINTR		0x08
#define EHCI_FRINDEX		0x0c
#define EHCI_CTRLDSSEGMENT	0x10
#define EHCI_PERIODICLISTBASE	0x14
#define EHCI_ASYNCLISTADDR	0x18
#define EHCI_CONFIGFLAG		0x40
#define  EHCI_CONFIGFLAG_FLAG		(1 << 0)
#define EHCI_PORTSC		0x44
#define  EHCI_PORTSC_PORT_OWNER			(1 << 13)
#define  EHCI_PORTSC_PORT_RESET			(1 << 12)
#define  EHCI_PORTSC_PORT_ENABLED		(1 << 2)
#define  EHCI_PORTSC_CONNECT_STATUS_CHANGED	(1 << 1)
#define  EHCI_PORTSC_CONNECTED			(1 << 0)

/* Off of ehci_debug_base */
#define EHCI_CTRL	0x00
#define  EHCI_CTRL_OWNER			(1 << 30)
#define  EHCI_CTRL_ENABLED			(1 << 28)
#define  EHCI_CTRL_DONE				(1 << 16)
#define  EHCI_CTRL_INUSE			(1 << 10)
#define  EHCI_CTRL_EXCEPTION_MASK		7
#define  EHCI_CTRL_EXCEPTION_SHIFT		7
#define  EHCI_CTRL_EXCEPTION_NONE		0
#define  EHCI_CTRL_EXCEPTION_TRANSACTION	1
#define  EHCI_CTRL_EXCEPTION_HARDWARE		2
#define  EHCI_CTRL_ERROR			(1 << 6)
#define  EHCI_CTRL_GO				(1 << 5)
#define  EHCI_CTRL_WRITE			(1 << 4)
#define  EHCI_CTRL_LENGTH_MASK			(0xf << 0)
#define EHCI_PID		0x04
#define  EHCI_PID_RECEIVED_SHIFT	16
#define  EHCI_PID_SEND_SHIFT		8
#define  EHCI_PID_TOKEN_SHIFT		0
#define EHCI_DATA0	0x08
#define EHCI_DATA1	0x0c
#define EHCI_ADDR	0x10
#define  EHCI_ADDR_DEVNUM_SHIFT   8
#define  EHCI_ADDR_ENDPOINT_SHIFT 0

#define MKPID(x) (((x) & 0xf) | ((~(x) & 0xf) << 4))

/* token */
#define PID_OUT	MKPID(0x1)
#define PID_IN	MKPID(0x9)
#define PID_SOF	MKPID(0x5)
#define PID_SETUP	MKPID(0xd)
/* data */
#define PID_DATA0	MKPID(0x3)
#define PID_DATA1	MKPID(0xb)
#define PID_DATA2	MKPID(0x7)
#define PID_MDATA	MKPID(0xf)
#define PID_DATA_TOGGLE	(0x88)
/* handshake */
#define PID_ACK	MKPID(0x2)
#define PID_NAK	MKPID(0xa)
#define PID_STALL	MKPID(0xe)
#define PID_NYET	MKPID(0x6)
/* Special */
#define PID_PRE	MKPID(0xc)
#define PID_ERR	MKPID(0xc)
#define PID_SPLIT	MKPID(0x8)
#define PID_PING	MKPID(0x4)
#define PID_RESERVED	MKPID(0x0)

/*
 * Standard requests
 */
#define USB_REQ_GET_STATUS              0x00
#define USB_REQ_CLEAR_FEATURE           0x01
/* 0x02 is reserved */
#define USB_REQ_SET_FEATURE             0x03
/* 0x04 is reserved */
#define USB_REQ_SET_ADDRESS             0x05
#define USB_REQ_GET_DESCRIPTOR          0x06
#define USB_REQ_SET_DESCRIPTOR          0x07
#define USB_REQ_GET_CONFIGURATION       0x08
#define USB_REQ_SET_CONFIGURATION       0x09
#define USB_REQ_GET_INTERFACE           0x0A
#define USB_REQ_SET_INTERFACE           0x0B
#define USB_REQ_SYNCH_FRAME             0x0C

#define USB_TYPE_STANDARD	(0x00 << 5)
#define USB_TYPE_CLASS		(0x01 << 5)
#define USB_TYPE_VENDOR		(0x02 << 5)
#define USB_TYPE_RESERVED	(0x03 << 5)

#define USB_RECIP_DEVICE                0x00
#define USB_RECIP_INTERFACE             0x01
#define USB_RECIP_ENDPOINT              0x02
#define USB_RECIP_OTHER                 0x03

/*
 * Various libusb API related stuff
 */

#define USB_ENDPOINT_IN                 0x80
#define USB_ENDPOINT_OUT                0x00

#ifndef USB_DT_DEBUG
#define USB_DT_DEBUG	10
#endif
#ifndef USB_FT_DEBUG_MODE
#define USB_FT_DEBUG_MODE	6
#endif 

struct usb_debug_descriptor {
	uint8_t	bLength;
	uint8_t bDescriptorType;
	uint8_t bDebugInEndpoint;
	uint8_t bDebugOutEndpoint;
} __attribute__ ((packed));

struct usb_status {
	uint16_t status;
} __attribute__ ((packed));


struct usb_request {
	uint8_t  bmRequestType;
	uint8_t  bRequest;
	uint16_t wValue;
	uint16_t wIndex;
	uint16_t wLength;
} __attribute__ ((packed));

static int usb_wait_until_complete(void)
{
	unsigned ctrl;
	for (;;) {
		ctrl = readl(ehci_debug_base + EHCI_CTRL);
		/* Stop when the transaction is finished */
		if (ctrl & EHCI_CTRL_DONE)
			break;
	}
	/* Now that we have observed the completed transaction,
	 * clear the done bit.
	 */
	writel(ctrl | EHCI_CTRL_DONE, ehci_debug_base + EHCI_CTRL);
	return (ctrl & EHCI_CTRL_ERROR) ? 
		-((ctrl >> EHCI_CTRL_EXCEPTION_SHIFT) & EHCI_CTRL_EXCEPTION_MASK):
		ctrl & 0xf;
}

static void usb_breath(void)
{
	struct timespec req;
	/* Sleep to give the debug port a chance to breathe */
	req.tv_sec = 0;
	req.tv_nsec = 10*1000*1000; /* 10 miliseconds seems good */

	while (nanosleep(&req, &req) < 0)
		;
}

static int usb_wait_until_done(unsigned ctrl)
{
	unsigned pids, lpid;
	int ret;

retry:
	writel(ctrl | EHCI_CTRL_GO, ehci_debug_base + EHCI_CTRL);
	ret = usb_wait_until_complete();
	pids = readl(ehci_debug_base + EHCI_PID);
	lpid = (pids >> EHCI_PID_RECEIVED_SHIFT) & 0xff;
#if 0
	if ((ret >= 0) && lpid != PID_ACK)
		printf("lpid: %02x ret: %d\n", lpid, ret);
#endif
	if (ret < 0)
		return ret;

	/* If the port is getting full or it has dropped data
	 * start pacing ourselves, not necessary but it's friendly.
	 */
	if ((lpid == PID_NAK) || (lpid == PID_NYET))
		usb_breath();
	
	/* If I get a NACK reissue the transmission */
	if (lpid == PID_NAK)
		goto retry;

	return ret;
}

static void usb_set_data(const void *buf, int size)
{
	const unsigned char *bytes = buf;
	uint32_t lo, hi;
	int i;
	lo = hi = 0;
	for (i = 0; i < 4 && i < size; i++)
		lo |= bytes[i] << (8*i);
	for (; i < 8 && i < size; i++)
		hi |= bytes[i] << (8*(i - 4));
	writel(lo, ehci_debug_base + EHCI_DATA0);
	writel(hi, ehci_debug_base + EHCI_DATA1);
}

static void usb_get_data(void *buf, int size)
{
	unsigned char *bytes = buf;
	uint32_t lo, hi;
	int i;
	lo = readl(ehci_debug_base + EHCI_DATA0);
	hi = readl(ehci_debug_base + EHCI_DATA1);
#if 0
	printf("data: %08x%08x\n", hi, lo);
#endif
	for (i = 0; i < 4 && i < size; i++)
		bytes[i] = (lo >> (8*i)) & 0xff;
	for (; i < 8 && i < size; i++)
		bytes[i] = (hi >> (8*(i - 4))) & 0xff;
}

static int usb_bulk_write(int address, int endpoint, const char *bytes, int size)
{
	unsigned pids, addr, ctrl;
	int ret;
	if (size > 8)
		return -1;

	addr = ((address & 0x7f) << EHCI_ADDR_DEVNUM_SHIFT) | (endpoint & 0xf);

	pids = readl(ehci_debug_base + EHCI_PID);
	pids &= ~(0xff << EHCI_PID_TOKEN_SHIFT);
	pids |= PID_OUT << EHCI_PID_TOKEN_SHIFT;
	pids ^= (PID_DATA_TOGGLE << EHCI_PID_SEND_SHIFT);
	
	ctrl = readl(ehci_debug_base + EHCI_CTRL);
	ctrl &= ~EHCI_CTRL_LENGTH_MASK;
	ctrl |= EHCI_CTRL_WRITE;
	ctrl |= size & EHCI_CTRL_LENGTH_MASK;
	ctrl |= EHCI_CTRL_GO;

	usb_set_data(bytes, size);
	writel(addr, ehci_debug_base + EHCI_ADDR);
	writel(pids, ehci_debug_base + EHCI_PID);

	ret = usb_wait_until_done(ctrl);
	if (ret < 0) {
		printf("out failed!: %d\n", ret);
		return ret;
	}
	return ret;
}

static int usb_bulk_read(int address, int endpoint, void *data, int size)
{
	unsigned pids, addr, ctrl;
	int ret;

	if (size > 8)
		return -1;

	addr = ((address & 0x7f) << EHCI_ADDR_DEVNUM_SHIFT) | (endpoint & 0xf);

	pids = readl(ehci_debug_base + EHCI_PID);
	pids &= ~(0xff << EHCI_PID_TOKEN_SHIFT);
	pids |= PID_IN << EHCI_PID_TOKEN_SHIFT;
	pids ^= (PID_DATA_TOGGLE << EHCI_PID_SEND_SHIFT);
		
	ctrl = readl(ehci_debug_base + EHCI_CTRL);
	ctrl &= ~EHCI_CTRL_LENGTH_MASK;
	ctrl &= ~EHCI_CTRL_WRITE;
	ctrl |= size & EHCI_CTRL_LENGTH_MASK;
	ctrl |= EHCI_CTRL_GO;
		
	writel(addr, ehci_debug_base + EHCI_ADDR);
	writel(pids, ehci_debug_base + EHCI_PID);
	ret = usb_wait_until_done(ctrl);
	if (ret < 0) {
		printf("in failed!: %d\n", ret);
		return ret;
	}
	if (size > ret)
		size = ret;
	usb_get_data(data, size);
	return ret;
}

static int usb_control_msg(int address, int requesttype, int request, 
	int value, int index, void *data, int size)
{
	unsigned pids, addr, ctrl;
	struct usb_request req;
	int read;
	int ret;

	read = (requesttype & USB_ENDPOINT_IN) != 0;
	if (size > (read?8:0))
		return -1;
	
	/* Compute the control message */
	req.bmRequestType = requesttype;
	req.bRequest = request;
	req.wValue = value;
	req.wIndex = index;
	req.wLength = size;

	pids = PID_SETUP << EHCI_PID_TOKEN_SHIFT;
	pids |= PID_DATA0 << EHCI_PID_SEND_SHIFT;

	addr = ((address & 0x7f) << EHCI_ADDR_DEVNUM_SHIFT) | 0;
	
	ctrl = readl(ehci_debug_base + EHCI_CTRL);
	ctrl &= ~EHCI_CTRL_LENGTH_MASK;
	ctrl |= EHCI_CTRL_WRITE;
	ctrl |= sizeof(req) & EHCI_CTRL_LENGTH_MASK;
	ctrl |= EHCI_CTRL_GO;

	/* Send the setup message */
	usb_set_data(&req, sizeof(req));
	writel(addr, ehci_debug_base + EHCI_ADDR);
	writel(pids, ehci_debug_base + EHCI_PID);
	ret = usb_wait_until_done(ctrl);
	if (ret < 0) {
		//printf("setup failed!: %d\n", ret);
		return ret;
	}


	/* Read the result */
	ret = usb_bulk_read(address, 0, data, size);
#if 1
	pids = readl(ehci_debug_base + EHCI_PID);
	printf("final pids: %08x ret: %d, size: %d\n", pids, ret, size);
#endif
	return ret;
}

static int usb_control_msg0(int address, int requesttype, int request, 
	int value, int index)
{
	return usb_control_msg(address, requesttype, request, value, index, NULL, 0);
}

int main(int argc, char **argv)
{
	struct usb_debug_descriptor debug;
	unsigned long ehci_bar, ehci_debug_offset;
	unsigned endpoint_out, endpoint_in;
	unsigned devnum;
	unsigned hcsparams;
	unsigned debug_port, n_ports;
	int fd;
	unsigned val;
	int result = -1;
	int ret, i;

	if (argc != 3)
		die("usage: %s <bar base> <bar offset>\n"
		     "ex:  ./usbdebug_direct 0xbfce0000 0x98\n"
		     "ex:  ./usbdebug_direct 0x90404400 0xa0\n",
			argv[0]);

	ehci_bar = strtoul(argv[1], NULL, 0);
	ehci_debug_offset = strtoul(argv[2], NULL, 0);
	
	fd = open("/dev/mem", O_RDWR, O_SYNC);
	if (fd < 0)
		die("Cannot open /dev/mem: %s\n", strerror(errno));

	ehci_base = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd,
		ehci_bar & ~(PAGE_SIZE - 1));
	if (ehci_base == MAP_FAILED)
		die("mmap of /dev/mem failed: %s\n", strerror(errno));

	ehci_base += ehci_bar & (PAGE_SIZE - 1);
	val = readb(ehci_base + EHCI_CAPLENGTH);
	ehci_op_base = ehci_base + val;
	ehci_debug_base = ehci_base + ehci_debug_offset;


	hcsparams = readl(ehci_base + EHCI_HCSPARAMS);
	debug_port = (hcsparams >> 20) & 0xf;
	n_ports = hcsparams & 0xf;

	printf("debug_port: %d\n", debug_port);
	printf("n_ports:    %d\n", n_ports);

	for (i = 1; i <= n_ports; i++) {
		val = readl(ehci_op_base + EHCI_PORTSC + (4*(i - 1)));
		printf("portsc%d: %08x\n", i, val);
	}
#if 0
	/* Reset the silly port */
#endif 
#if 0
	/* Claim ownership, but do not enable yet */
	val = readl(ehci_debug_base + EHCI_CTRL);
	printf("ctrl: %08x\n", val);
	val |= EHCI_CTRL_OWNER;
	val &= ~(EHCI_CTRL_ENABLED | EHCI_CTRL_INUSE);
	writel(val, ehci_debug_base + EHCI_CTRL);

	val = readl(ehci_debug_base + EHCI_CTRL);
	printf("ctrl: %08x\n", val);


#if 1
	/* Ensure everything is routed to the EHCI */
	val = readl(ehci_op_base + EHCI_CONFIGFLAG);
	val |= EHCI_CONFIGFLAG_FLAG;
	writel(val, ehci_op_base + EHCI_CONFIGFLAG);


	for (i = 1; i <= n_ports; i++) {
		val = readl(ehci_op_base + EHCI_PORTSC + (4*(i - 1)));
		printf("portsc%d: %08x\n", i, val);
	}
#endif

	/* Ensure the EHCI controller is running */
	val = readl(ehci_op_base + EHCI_USBCMD);
	val |= EHCI_USBCMD_RUN;
	writel(val, ehci_op_base + EHCI_USBCMD);

	while(readl(ehci_op_base + EHCI_USBSTS) & EHCI_USBSTS_HCHALTED)
		;

	/* Reset the usb debug port */
	val = readl(ehci_op_base + EHCI_PORTSC + 4*(debug_port - 1));
	val |= EHCI_PORTSC_PORT_RESET;
	writel(val, ehci_op_base + EHCI_PORTSC + 4*(debug_port - 1));
	
	/* Sleep long enough for the reset to take effect */
	usb_breath(); /* 10 millseconds */

	/* Stop the reset of the usb debug port */
	val &= ~EHCI_PORTSC_PORT_RESET;
	writel(val, ehci_op_base + EHCI_PORTSC + 4*(debug_port - 1));


	for (i = 1; i <= n_ports; i++) {
		val = readl(ehci_op_base + EHCI_PORTSC + (4*(i - 1)));
		printf("portsc%d: %08x\n", i, val);
	}

	/* Test to see if there is an attached device */
	val = readl(ehci_op_base + EHCI_PORTSC + 4*(debug_port - 1));
	if (!(val & EHCI_PORTSC_CONNECTED)) {
		printf("No device in debug port after reset \n");
		/* Give up the device */
		return -1;
	}

	/* Enable the debug port */
	val = readl(ehci_debug_base + EHCI_CTRL);
	printf("post reset ctrl: %08x\n", val);

	val |= EHCI_CTRL_ENABLED | EHCI_CTRL_INUSE;
	writel(val, ehci_debug_base + EHCI_CTRL);

	val = readl(ehci_debug_base + EHCI_CTRL);
	printf("post reset ctrl: %08x\n", val);

# if 1
	/* Hide the presence of this device from other software */
	val = readl(ehci_op_base + EHCI_PORTSC + 4*(debug_port - 1));
	val &= ~EHCI_PORTSC_PORT_ENABLED;
	writel(val, ehci_op_base + EHCI_PORTSC + 4*(debug_port - 1));
# endif
# if 1
	/* Disable the ehci controller */
	val = readl(ehci_op_base + EHCI_USBCMD);
	val &= ~EHCI_USBCMD_RUN;
	writel(val, ehci_op_base + EHCI_USBCMD);

	while(!(readl(ehci_op_base + EHCI_USBSTS) & EHCI_USBSTS_HCHALTED))
		;
# endif
#else
#define EHCI_CTRL_CLAIM (EHCI_CTRL_OWNER | EHCI_CTRL_ENABLED | EHCI_CTRL_INUSE)
	val  = readl(ehci_debug_base + EHCI_CTRL);
	printf("ctrl: %04x\n", val);

	writel(val | EHCI_CTRL_CLAIM, ehci_debug_base + EHCI_CTRL);

	val  = readl(ehci_debug_base + EHCI_CTRL);
	printf("ctrl: %04x\n", val);
	if ((val & EHCI_CTRL_CLAIM) != EHCI_CTRL_CLAIM) {
		printf("No device in debug port\n");
		writel(val & ~EHCI_CTRL_CLAIM, ehci_debug_base + EHCI_CTRL);
		return -1;
	}
	
#endif

	printf("Find the debug device!\n");

	/* Find the debug device and make it device number 127 */
	for (devnum = 0; devnum <= 127; devnum++) {
		//printf("devnum: %d\n", devnum);
		ret = usb_control_msg(devnum, 
			USB_ENDPOINT_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
			USB_REQ_GET_DESCRIPTOR, (USB_DT_DEBUG << 8), 0,
			&debug, sizeof(debug));
		if (ret > 0)
			break;
	}
	if (devnum > 127) {
		printf("Could not find attached debug device\n");
		goto err;
	}
	if (ret < 0) {
		printf("Attach device is not a debug device\n");
		goto err;
	}
	printf("devnum: %d\n", devnum);
	endpoint_out = debug.bDebugOutEndpoint;
	endpoint_in = debug.bDebugInEndpoint;


	/* Move the device to 127 if it isn't already there */
	if (devnum != 127) {
		ret = usb_control_msg0(devnum,
			USB_TYPE_STANDARD | USB_RECIP_DEVICE,
			USB_REQ_SET_ADDRESS, 127, 0);
		printf("set_address: %d\n", ret);
		if (ret < 0) {
			printf("Could not move attached device to 127\n");
			goto err;
		}
		devnum = 127;
	}

	/* Enable the debug interface */
	ret = usb_control_msg0(devnum, USB_TYPE_STANDARD | USB_RECIP_DEVICE,
		USB_REQ_SET_FEATURE, USB_FT_DEBUG_MODE, 0);
	printf("set_feature_debug_mode: %d\n", ret);
	if (ret < 0) {
		printf(" Could not enable the debug device\n");
		goto err;
	}

#if 1
	{
		//unsigned devnum = 2;
		//unsigned endpoint_out = 1;
		//unsigned endpoint_in = 0x82;
		char *test_strings[] = {
			"zero\n",
			"one\n",
			"two\n",
			"three\n",
			"four\n",
			"five\n",
			"six\n",
			"seven\n",
			"eight\n",
			"nine\n",
			"ten\n",
			"eleven\n",
#if 0
			"twelve\n",
#endif
			NULL,
		};
		char **ptr;

		/* Perform a small write to get the even/odd data state in sync
		 */
		ret = usb_bulk_write(devnum, endpoint_out, " ",1);
		printf("usb_bulk_write: %d\n", ret);

		/* Write the test messages */
		for (ptr = test_strings; *ptr; ptr++) {
			/* Write a test message */
			ret = usb_bulk_write(devnum, endpoint_out,
				*ptr, strlen(*ptr));
			printf("usb_bulk_write: %d\n", ret);
		}
	}
#endif
#if 0

	/* Read some test messages */
	for (;;) {
		char buf[8];
		ret = usb_bulk_read(devnum, endpoint_in, 
			buf, sizeof(buf));
		if (ret > 0)
			printf("%d:%*.*s", ret, ret, ret, buf);
	}
#endif
	for (i = 0; i < 256; i+=1) {
		val = readb(ehci_base + i);
		printf("%02x ", val);
		if ((i & 0xf) == 0xf)
			printf("\n");
	}
	printf("\n");

	result = 0;
err:
#ifdef EHCI_CTRL_CLAIM
	val = readl(ehci_debug_base + EHCI_CTRL);
	printf("ctrl: %08x\n", val);
	val &= ~(EHCI_CTRL_CLAIM | EHCI_CTRL_WRITE);
	writel(val, ehci_debug_base + EHCI_CTRL);
	val = readl(ehci_debug_base + EHCI_CTRL);
	printf("ctrl: %08x\n", val);
#endif
	return result;
	
}

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [LinuxBIOS] #57: libusb host program for PLX NET20DC debug device
  2006-12-01 19:19 ` Greg KH
  2006-12-01 20:42   ` Peter Stuge
  2006-12-01 23:13   ` Eric W. Biederman
@ 2006-12-03 15:49   ` Eric W. Biederman
  2006-12-04  5:09     ` [RFC][PATCH 0/2] x86_64 Early usb debug port support Eric W. Biederman
  2 siblings, 1 reply; 29+ messages in thread
From: Eric W. Biederman @ 2006-12-03 15:49 UTC (permalink / raw)
  To: Greg KH
  Cc: Lu, Yinghai, Stefan Reinauer, Peter Stuge, linuxbios, linux-kernel

Greg KH <gregkh@suse.de> writes:

> On Fri, Dec 01, 2006 at 10:55:48AM -0800, Lu, Yinghai wrote:
>> -----Original Message-----
>> From: Greg KH [mailto:gregkh@suse.de] 
>> 
>> >I can do that in about 15 minutes if you give me the device ids for the
>> >usb debug device that you wish to have.
>> 
>> >Or you can also use the generic usb-serial driver today just fine with
>> >no modification.  Have you had a problem with using that option?
>> 
>> We are talking about using USB debug device/EHCI debug port in LinuxBIOS
>> in legacy free PC.
>> Because one AM2+MCP55 MB doesn't have serial port.
>> 
>> I guess Eric is working on USB debug device/EHCI debug port for
>> earlyprintk or printk.
>
> Well, earlyprintk will not work, as you need PCI up and running.

*grin*  I just generated the bootlog below.  So I think I have
it working.  There is a lot of cleanup left and I need some sleep but
it works for me.  I will generate a patch to start the conversation
after I wake up.

> And I have some code that barely works for this already, perhaps Eric
> and I should work together on this :)

Eric


Linux version 2.6.19-rc6devel (eric@fess.biederman.org) (gcc version 4.1.1 2006
0525 (Red Hat 4.1.1-1)) #153 SMP Sun Dec 3 07:56:52 MST 2006
Command line: ro root=LABEL=/ rhgb earlyprintk=dbgp console=tty0 console=ttyS0,1
15200 panic=30
BIOS-provided physical RAM map:
 BIOS-e820: 0000000000000000 - 000000000009fc00 (usable)
 BIOS-e820: 000000000009fc00 - 00000000000a0000 (reserved)
 BIOS-e820: 00000000000e6000 - 0000000000100000 (reserved)
 BIOS-e820: 0000000000100000 - 000000009ffd0000 (usable)
 BIOS-e820: 000000009ffd0000 - 000000009ffde000 (ACPI data)
 BIOS-e820: 000000009ffde000 - 00000000a0000000 (ACPI NVS)
 BIOS-e820: 00000000fec00000 - 00000000fec01000 (reserved)
 BIOS-e820: 00000000fee00000 - 00000000fee01000 (reserved)
 BIOS-e820: 00000000ff780000 - 0000000100000000 (reserved)
 BIOS-e820: 0000000100000000 - 000000024c000000 (usable)
end_pfn_map = 2408448
kernel direct mapping tables up to 24c000000 @ 8000-13000
DMI 2.3 present.
SRAT: PXM 0 -> APIC 0 -> Node 0
SRAT: PXM 0 -> APIC 1 -> Node 0
SRAT: PXM 1 -> APIC 2 -> Node 1
SRAT: PXM 1 -> APIC 3 -> Node 1
SRAT: Node 0 PXM 0 100000-a0000000
SRAT: Node 1 PXM 1 14c000000-24c000000
SRAT: Node 0 PXM 0 100000-14c000000
SRAT: Node 0 PXM 0 0-14c000000
Bootmem setup node 0 0000000000000000-000000014c000000
Bootmem setup node 1 000000014c000000-000000024c000000
Zone PFN ranges:
  DMA             0 ->     4096
  DMA32        4096 ->  1048576
  Normal    1048576 ->  2408448
early_node_map[4] active PFN ranges
    0:        0 ->      159
    0:      256 ->   655312
    0:  1048576 ->  1359872
    1:  1359872 ->  2408448
Nvidia board detected. Ignoring ACPI timer override.
If you got timer trouble try acpi_use_timer_override
ACPI: PM-Timer IO Port: 0x4008
ACPI: LAPIC (acpi_id[0x01] lapic_id[0x00] enabled)
Processor #0 (Bootup-CPU)
ACPI: LAPIC (acpi_id[0x02] lapic_id[0x01] enabled)
Processor #1
ACPI: LAPIC (acpi_id[0x03] lapic_id[0x02] enabled)
Processor #2
ACPI: LAPIC (acpi_id[0x04] lapic_id[0x03] enabled)
Processor #3
ACPI: IOAPIC (id[0x04] address[0xfec00000] gsi_base[0])
IOAPIC[0]: apic_id 4, address 0xfec00000, GSI 0-23
ACPI: IOAPIC (id[0x05] address[0xdfefc000] gsi_base[24])
IOAPIC[1]: apic_id 5, address 0xdfefc000, GSI 24-47
ACPI: INT_SRC_OVR (bus 0 bus_irq 0 global_irq 2 dfl dfl)
ACPI: BIOS IRQ0 pin2 override ignored.
ACPI: INT_SRC_OVR (bus 0 bus_irq 9 global_irq 9 high level)
Setting APIC routing to flat
Using ACPI (MADT) for SMP configuration information
Nosave address range: 000000000009f000 - 00000000000a0000
Nosave address range: 00000000000a0000 - 00000000000e6000
Nosave address range: 00000000000e6000 - 0000000000100000
Nosave address range: 000000009ffd0000 - 000000009ffde000
Nosave address range: 000000009ffde000 - 00000000a0000000
Nosave address range: 00000000a0000000 - 00000000fec00000
Nosave address range: 00000000fec00000 - 00000000fec01000
Nosave address range: 00000000fec01000 - 00000000fee00000
Nosave address range: 00000000fee00000 - 00000000fee01000
Nosave address range: 00000000fee01000 - 00000000ff780000
Nosave address range: 00000000ff780000 - 0000000100000000
Allocating PCI resources starting at a8000000 (gap: a0000000:5ec00000)
PERCPU: Allocating 66560 bytes of per cpu data
Built 2 zonelists.  Total pages: 1960348
Kernel command line: ro root=LABEL=/ rhgb earlyprintk=dbgp console=tty0 console=
ttyS0,115200 panic=30
Initializing CPU#0
PID hash table entries: 4096 (order: 12, 32768 bytes)
disabling early console

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [LinuxBIOS] #57: libusb host program for PLX NET20DC debug device
  2006-12-01 23:02         ` Eric W. Biederman
@ 2006-12-03 17:00           ` Peter Stuge
  2006-12-03 23:03             ` Eric W. Biederman
  0 siblings, 1 reply; 29+ messages in thread
From: Peter Stuge @ 2006-12-03 17:00 UTC (permalink / raw)
  To: Eric W. Biederman; +Cc: Greg KH, linux-kernel, Andi Kleen, linuxbios

On Fri, Dec 01, 2006 at 04:02:03PM -0700, Eric W. Biederman wrote:
> >> Sure, I will send it out shortly.  I currently have a working
> >> user space libusb thing (easy, but useful for my debug)
> >
> > Hm - for driving which end?
> 
> Either.  The specific device we are talking about doesn't care.

Which device do you have?


> > The debug port isn't really supposed to be used with anything but
> > a debug device - which can't be enumerated normally anyway.
> 
> It depends.  If you have a debug cable with magic ends and a
> hardcoded address of 127 the normal enumeration doesn't work.  I
> don't think anyone actually makes one of those.

Only one of the ports on Stefan's PLX NET20DC that I had a look at
during the LinuxBIOS symposium enumerated for me.


> Debug devices are also allowed to be normal devices that just
> support the debug descriptor.  Which is what I'm working with.

Aye. I would be happy if we could get something out, as you have
done! :) Looking forward to trying it, I hope I get my device soon.


//Peter

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [LinuxBIOS] #57: libusb host program for PLX NET20DC debug device
  2006-12-03 17:00           ` Peter Stuge
@ 2006-12-03 23:03             ` Eric W. Biederman
  0 siblings, 0 replies; 29+ messages in thread
From: Eric W. Biederman @ 2006-12-03 23:03 UTC (permalink / raw)
  To: Peter Stuge; +Cc: Greg KH, linux-kernel, Andi Kleen, linuxbios

Peter Stuge <stuge-linuxbios@cdy.org> writes:

> On Fri, Dec 01, 2006 at 04:02:03PM -0700, Eric W. Biederman wrote:
>> >> Sure, I will send it out shortly.  I currently have a working
>> >> user space libusb thing (easy, but useful for my debug)
>> >
>> > Hm - for driving which end?
>> 
>> Either.  The specific device we are talking about doesn't care.
>
> Which device do you have?

Well it is built by PLX, and from lsusb I see are:
0525:127a Netchip Technology, Inc. 

The hardware is a little rectangular pcb board a little smaller
then a business card.  Wrapped in a blue case, with vertical vents
on both of the long sides, and gets a little warm when you have been
running it for a while.  The device has what appears to be 2 normal
host to slave cables running into it.

The picture at the bottom of:
http://advdbg.org/blogs/advdbg_system/articles/64.aspx

Looks like what I have.  I'm curious about the whole plug both
ends into the host before plugging it into the client, and about
the strange target system BIOS requirements.

I think I succeeded in making it work without out that by just putting
in a reset.  It does make the whole setup of the device a pain though.

>> > The debug port isn't really supposed to be used with anything but
>> > a debug device - which can't be enumerated normally anyway.
>> 
>> It depends.  If you have a debug cable with magic ends and a
>> hardcoded address of 127 the normal enumeration doesn't work.  I
>> don't think anyone actually makes one of those.
>
> Only one of the ports on Stefan's PLX NET20DC that I had a look at
> during the LinuxBIOS symposium enumerated for me.

Very odd.  I'm pretty certain we are talking same thing.  But I do
know it has a couple of weird quirks, so maybe you just ran up against
that.

>> Debug devices are also allowed to be normal devices that just
>> support the debug descriptor.  Which is what I'm working with.
>
> Aye. I would be happy if we could get something out, as you have
> done! :) Looking forward to trying it, I hope I get my device soon.

Well at least this means after it works I can probably forget about
it and let someone else maintain the code ;)

Eric

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [RFC][PATCH 0/2] x86_64 Early usb debug port support.
  2006-12-03 15:49   ` Eric W. Biederman
@ 2006-12-04  5:09     ` Eric W. Biederman
  2006-12-04  5:13       ` [RFC][PATCH 1/2] x86_64: Preallocate the fixmap pud and pmd entries Eric W. Biederman
       [not found]       ` <200612042001.09808.david-b@pacbell.net>
  0 siblings, 2 replies; 29+ messages in thread
From: Eric W. Biederman @ 2006-12-04  5:09 UTC (permalink / raw)
  To: USB development list
  Cc: Greg KH, Lu, Yinghai, Stefan Reinauer, Peter Stuge, linuxbios,
	linux-kernel, Andi Kleen


With legacy free systems serial ports have stopped being an option
to get early boot traces and other debug information out of a machine.

EHCI USB controllers provide a relatively simple debug interface
that can control port 1 of the root hub.  This interface is limited
to 8 byte packets so it can be used with most USB devices.  But with
a USB debug device this is sufficient to talk to another machine.

When the special feature of the EHCI is not enabled the port
1 of the root hub acts just like any other USB port so machines
with the necessary support are widely available.

This debug device can be used to replace serial ports for
kgdb, kdb, and console support.  And gregkh has a simple usb
serial driver for it so user space applications that control
serial ports should work unmodified.

Currently there only appears to be one manufacturer of debug
devices see:
http://www.plxtech.com/products/NET2000/NET20DC/default.asp

I think simple RS232 serial ports provide a nicer and simpler
interface but the usb debug port looks like a functional alternative
when you don't have that.

My code likely doesn't handle all of the corner cases yet, and needs
a little more work to integrate cleanly into the build.  But this
is getting it out there so other people can look and help make clean
drivers.  When writing a polling driver you do have to be careful
with your logic, because if you do things like reset a usb device at
the wrong time you can completely confuse various EHCI controllers.

My driver should be sufficient to work with any EHCI in a realatively
clean state, and needs no special BIOS support just the hardware.
This appears to be different than the way the windows drivers are
using these debug devices.

Eric


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [RFC][PATCH 1/2] x86_64:  Preallocate the fixmap pud and pmd entries.
  2006-12-04  5:09     ` [RFC][PATCH 0/2] x86_64 Early usb debug port support Eric W. Biederman
@ 2006-12-04  5:13       ` Eric W. Biederman
  2006-12-04  5:18         ` [RFC][PATCH 2/2] x86_64: earlyprintk usb debug device support Eric W. Biederman
       [not found]       ` <200612042001.09808.david-b@pacbell.net>
  1 sibling, 1 reply; 29+ messages in thread
From: Eric W. Biederman @ 2006-12-04  5:13 UTC (permalink / raw)
  To: USB development list
  Cc: Greg KH, Lu, Yinghai, Stefan Reinauer, Peter Stuge, linuxbios,
	linux-kernel, Andi Kleen


To use the debug device I need to work through a port so I need
to call ioreamp or similar.  Since we are doing this very early
I chose to use a fixmap (because we are unlikely to free the mapping)
and because it is simple.  If we preallocate the fixmap pud and pmd
entries the existing fixmap codes works anytime from power up without
modifications or memory allocations.  So we don't need a special case.

---
 arch/x86_64/kernel/head.S |   11 ++++++++++-
 1 files changed, 10 insertions(+), 1 deletions(-)

diff --git a/arch/x86_64/kernel/head.S b/arch/x86_64/kernel/head.S
index 2f65469..4004965 100644
--- a/arch/x86_64/kernel/head.S
+++ b/arch/x86_64/kernel/head.S
@@ -271,7 +271,16 @@ NEXT_PAGE(level3_kernel_pgt)
 	.fill	510,8,0
 	/* (2^48-(2*1024*1024*1024)-((2^39)*511))/(2^30) = 510 */
 	.quad	phys_level2_kernel_pgt | 0x007
-	.fill	1,8,0
+	.quad	phys_level2_fixmap_pgt | 0x007
+
+NEXT_PAGE(level2_fixmap_pgt)
+	.fill	506,8,0
+	.quad	phys_level1_fixmap_pgt | 0x007
+	/* 8MB reserved for vsyscalls + a 2MB hole = 4 + 1 entries */
+	.fill	5,8,0
+
+NEXT_PAGE(level1_fixmap_pgt)
+	.fill	512,8,0
 
 NEXT_PAGE(level2_ident_pgt)
 	/* 40MB for bootup. 	*/
-- 
1.4.2.rc3.g7e18e-dirty


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [RFC][PATCH 2/2] x86_64: earlyprintk usb debug device support.
  2006-12-04  5:13       ` [RFC][PATCH 1/2] x86_64: Preallocate the fixmap pud and pmd entries Eric W. Biederman
@ 2006-12-04  5:18         ` Eric W. Biederman
  0 siblings, 0 replies; 29+ messages in thread
From: Eric W. Biederman @ 2006-12-04  5:18 UTC (permalink / raw)
  To: USB development list
  Cc: Greg KH, Lu, Yinghai, Stefan Reinauer, Peter Stuge, linuxbios,
	linux-kernel, Andi Kleen


This patch is still a little rough but it gets all of the major pieces
correct.  With a little more work this should become a maintainable
driver.

In particular I believe the ehci debug port code is fairly solid
(with rough edges).  However there are several nasty bits that
need to be resolved before we can push this upstream.  Like
my include of ehci.h  And general early kernel space dependency
problems.

But the code works for me so it should at least be a reasonable starting
point for others looking to make the debug port work in a reasonable fashion.

Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
---
 arch/x86_64/kernel/early_printk.c |  574 +++++++++++++++++++++++++++++++++++++
 drivers/usb/host/ehci.h           |    8 +
 include/asm-x86_64/fixmap.h       |    1 
 3 files changed, 583 insertions(+), 0 deletions(-)

diff --git a/arch/x86_64/kernel/early_printk.c b/arch/x86_64/kernel/early_printk.c
index d4050a5..cb5182d 100644
--- a/arch/x86_64/kernel/early_printk.c
+++ b/arch/x86_64/kernel/early_printk.c
@@ -3,9 +3,19 @@ #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/string.h>
 #include <linux/screen_info.h>
+#include <linux/usb_ch9.h>
+#include <linux/pci_regs.h>
+#include <linux/pci_ids.h>
+#include <linux/errno.h>
 #include <asm/io.h>
 #include <asm/processor.h>
 #include <asm/fcntl.h>
+#include <asm/pci-direct.h>
+#include <asm/pgtable.h>
+#include <asm/fixmap.h>
+#define EARLY_PRINTK
+#include "../../../drivers/usb/host/ehci.h"
+
 
 /* Simple VGA output */
 
@@ -155,6 +165,558 @@ static struct console early_serial_conso
 	.index =	-1,
 };
 
+
+static struct ehci_caps __iomem *ehci_caps;
+static struct ehci_regs __iomem *ehci_regs;
+static struct ehci_dbg_port __iomem *ehci_debug;
+static unsigned dbgp_endpoint_out;
+
+#define USB_DEBUG_DEVNUM 127
+
+#define DBGP_DATA_TOGGLE	0x8800
+#define DBGP_PID_UPDATE(x, tok) \
+	((((x) ^ DBGP_DATA_TOGGLE) & 0xffff00) | ((tok) & 0xff))
+
+#define DBGP_LEN_UPDATE(x, len) (((x) & ~0x0f) | ((len) & 0x0f))
+/*
+ * USB Packet IDs (PIDs)
+ */
+
+/* token */
+#define USB_PID_OUT		0xe1
+#define USB_PID_IN		0x69
+#define USB_PID_SOF		0xa5
+#define USB_PID_SETUP		0x2d
+/* handshake */
+#define USB_PID_ACK		0xd2
+#define USB_PID_NAK		0x5a
+#define USB_PID_STALL		0x1e
+#define USB_PID_NYET		0x96
+/* data */
+#define USB_PID_DATA0		0xc3
+#define USB_PID_DATA1		0x4b
+#define USB_PID_DATA2		0x87
+#define USB_PID_MDATA		0x0f
+/* Special */
+#define USB_PID_PREAMBLE	0x3c
+#define USB_PID_ERR		0x3c
+#define USB_PID_SPLIT		0x78
+#define USB_PID_PING		0xb4
+#define USB_PID_UNDEF_0		0xf0
+
+#define USB_PID_DATA_TOGGLE	0x88
+#define DBGP_CLAIM (DBGP_OWNER | DBGP_ENABLED | DBGP_INUSE)
+
+#define PCI_CAP_ID_EHCI_DEBUG	0xa
+
+#define HUB_ROOT_RESET_TIME	50	/* times are in msec */
+#define HUB_SHORT_RESET_TIME	10
+#define HUB_LONG_RESET_TIME	200
+#define HUB_RESET_TIMEOUT	500
+
+#define DBGP_MAX_PACKET		8
+
+static int dbgp_wait_until_complete(void)
+{
+	unsigned ctrl;
+	for (;;) {
+		ctrl = readl(&ehci_debug->control);
+		/* Stop when the transaction is finished */
+		if (ctrl & DBGP_DONE)
+			break;
+	}
+	/* Now that we have observed the completed transaction,
+	 * clear the done bit.
+	 */
+	writel(ctrl | DBGP_DONE, &ehci_debug->control);
+	return (ctrl & DBGP_ERROR) ? -DBGP_ERRCODE(ctrl) : DBGP_LEN(ctrl);
+}
+
+static void dbgp_mdelay(int ms)
+{
+	int i;
+	while (ms--) {
+		for (i = 0; i < 1000; i++)
+			outb(0x1, 0x80);
+	}
+}
+
+static void dbgp_breath(void)
+{
+	/* Sleep to give the debug port a chance to breathe */
+}
+
+static int dbgp_wait_until_done(unsigned ctrl)
+{
+	unsigned pids, lpid;
+	int ret;
+
+retry:
+	writel(ctrl | DBGP_GO, &ehci_debug->control);
+	ret = dbgp_wait_until_complete();
+	pids = readl(&ehci_debug->pids);
+	lpid = DBGP_PID_GET(pids);
+
+	if (ret < 0)
+		return ret;
+
+	/* If the port is getting full or it has dropped data
+	 * start pacing ourselves, not necessary but it's friendly.
+	 */
+	if ((lpid == USB_PID_NAK) || (lpid == USB_PID_NYET))
+		dbgp_breath();
+	
+	/* If I get a NACK reissue the transmission */
+	if (lpid == USB_PID_NAK)
+		goto retry;
+
+	return ret;
+}
+
+static void dbgp_set_data(const void *buf, int size)
+{
+	const unsigned char *bytes = buf;
+	unsigned lo, hi;
+	int i;
+	lo = hi = 0;
+	for (i = 0; i < 4 && i < size; i++)
+		lo |= bytes[i] << (8*i);
+	for (; i < 8 && i < size; i++)
+		hi |= bytes[i] << (8*(i - 4));
+	writel(lo, &ehci_debug->data03);
+	writel(hi, &ehci_debug->data47);
+}
+
+static void dbgp_get_data(void *buf, int size)
+{
+	unsigned char *bytes = buf;
+	unsigned lo, hi;
+	int i;
+	lo = readl(&ehci_debug->data03);
+	hi = readl(&ehci_debug->data47);
+	for (i = 0; i < 4 && i < size; i++)
+		bytes[i] = (lo >> (8*i)) & 0xff;
+	for (; i < 8 && i < size; i++)
+		bytes[i] = (hi >> (8*(i - 4))) & 0xff;
+}
+
+static int dbgp_bulk_write(unsigned devnum, unsigned endpoint, const char *bytes, int size)
+{
+	unsigned pids, addr, ctrl;
+	int ret;
+	if (size > DBGP_MAX_PACKET)
+		return -1;
+
+	addr = DBGP_EPADDR(devnum, endpoint);
+
+	pids = readl(&ehci_debug->pids);
+	pids = DBGP_PID_UPDATE(pids, USB_PID_OUT);
+	
+	ctrl = readl(&ehci_debug->control);
+	ctrl = DBGP_LEN_UPDATE(ctrl, size);
+	ctrl |= DBGP_OUT;
+	ctrl |= DBGP_GO;
+
+	dbgp_set_data(bytes, size);
+	writel(addr, &ehci_debug->address);
+	writel(pids, &ehci_debug->pids);
+
+	ret = dbgp_wait_until_done(ctrl);
+	if (ret < 0) {
+		return ret;
+	}
+	return ret;
+}
+
+static int dbgp_bulk_read(unsigned devnum, unsigned endpoint, void *data, int size)
+{
+	unsigned pids, addr, ctrl;
+	int ret;
+
+	if (size > DBGP_MAX_PACKET)
+		return -1;
+
+	addr = DBGP_EPADDR(devnum, endpoint);
+
+	pids = readl(&ehci_debug->pids);
+	pids = DBGP_PID_UPDATE(pids, USB_PID_IN);
+		
+	ctrl = readl(&ehci_debug->control);
+	ctrl = DBGP_LEN_UPDATE(ctrl, size);
+	ctrl &= ~DBGP_OUT;
+	ctrl |= DBGP_GO;
+		
+	writel(addr, &ehci_debug->address);
+	writel(pids, &ehci_debug->pids);
+	ret = dbgp_wait_until_done(ctrl);
+	if (ret < 0)
+		return ret;
+	if (size > ret)
+		size = ret;
+	dbgp_get_data(data, size);
+	return ret;
+}
+
+static int dbgp_control_msg(unsigned devnum, int requesttype, int request, 
+	int value, int index, void *data, int size)
+{
+	unsigned pids, addr, ctrl;
+	struct usb_ctrlrequest req;
+	int read;
+	int ret;
+
+	read = (requesttype & USB_DIR_IN) != 0;
+	if (size > (read?DBGP_MAX_PACKET:0))
+		return -1;
+	
+	/* Compute the control message */
+	req.bRequestType = requesttype;
+	req.bRequest = request;
+	req.wValue = value;
+	req.wIndex = index;
+	req.wLength = size;
+
+	pids = DBGP_PID_SET(USB_PID_DATA0, USB_PID_SETUP);
+	addr = DBGP_EPADDR(devnum, 0);
+
+	ctrl = readl(&ehci_debug->control);
+	ctrl = DBGP_LEN_UPDATE(ctrl, sizeof(req));
+	ctrl |= DBGP_OUT;
+	ctrl |= DBGP_GO;
+
+	/* Send the setup message */
+	dbgp_set_data(&req, sizeof(req));
+	writel(addr, &ehci_debug->address);
+	writel(pids, &ehci_debug->pids);
+	ret = dbgp_wait_until_done(ctrl);
+	if (ret < 0)
+		return ret;
+
+
+	/* Read the result */
+	ret = dbgp_bulk_read(devnum, 0, data, size);
+	return ret;
+}
+
+
+/* Find a PCI capability */
+static __u32 __init find_cap(int num, int slot, int func, int cap) 
+{ 
+	u8 pos;
+	int bytes;
+	if (!(read_pci_config_16(num,slot,func,PCI_STATUS) & PCI_STATUS_CAP_LIST))
+		return 0;
+	pos = read_pci_config_byte(num,slot,func,PCI_CAPABILITY_LIST);
+	for (bytes = 0; bytes < 48 && pos >= 0x40; bytes++) { 
+		u8 id;
+		pos &= ~3; 
+		id = read_pci_config_byte(num,slot,func,pos+PCI_CAP_LIST_ID);
+		if (id == 0xff)
+			break;
+		if (id == cap) 
+			return pos; 
+		pos = read_pci_config_byte(num,slot,func,pos+PCI_CAP_LIST_NEXT); 
+	} 
+	return 0;
+} 
+
+static __u32 __init find_dbgp(int ehci_num, unsigned *rbus, unsigned *rslot, unsigned *rfunc)
+{
+	unsigned bus, slot, func;
+	
+	for (bus = 0; bus < 256; bus++) {
+		for (slot = 0; slot < 32; slot++) {
+			for (func = 0; func < 8; func++) {
+				u32 class;
+				unsigned cap;
+				class = read_pci_config(bus, slot, func, PCI_CLASS_REVISION);
+				if ((class >> 8) != PCI_CLASS_SERIAL_USB_EHCI)
+					continue;
+				cap = find_cap(bus, slot, func, PCI_CAP_ID_EHCI_DEBUG);
+				if (!cap)
+					continue;
+				if (ehci_num-- != 0)
+					continue;
+				*rbus = bus;
+				*rslot = slot;
+				*rfunc = func;
+				return cap;
+			}
+		}
+	}
+	return 0;
+}
+
+static int ehci_reset_port(int port)
+{
+	unsigned portsc;
+	unsigned delay_time, delay;
+
+	/* Reset the usb debug port */
+	portsc = readl(&ehci_regs->port_status[port - 1]);
+	portsc &= ~PORT_PE;
+	portsc |= PORT_RESET;
+	writel(portsc, &ehci_regs->port_status[port - 1]);
+
+	delay = HUB_ROOT_RESET_TIME;
+	for (delay_time = 0; delay_time < HUB_RESET_TIMEOUT;
+	     delay_time += delay) {
+		dbgp_mdelay(delay);
+
+		portsc = readl(&ehci_regs->port_status[port - 1]);
+		if (portsc & PORT_RESET) {
+			/* force reset to complete */
+			writel(portsc & ~(PORT_RWC_BITS | PORT_RESET), 
+				&ehci_regs->port_status[port - 1]);
+			while (portsc & PORT_RESET)
+				portsc = readl(&ehci_regs->port_status[port - 1]);
+		}
+
+		/* Device went away? */
+		if (!(portsc & PORT_CONNECT))
+			return -ENOTCONN;
+
+		/* bomb out completely if something weird happend */
+		if ((portsc & PORT_CSC))
+			return -EINVAL;
+
+		/* If we've finished resetting, then break out of the loop */
+		if (!(portsc & PORT_RESET) && (portsc & PORT_PE))
+			return 0;
+	}
+	return -EBUSY;
+}
+
+static int ehci_wait_for_port(int port)
+{
+	unsigned status;
+	int ret, reps;
+	for (reps = 0; reps >= 0; reps++) {
+		status = readl(&ehci_regs->status);
+		if (status & STS_PCD) {
+			ret = ehci_reset_port(port);
+			if (ret == 0)
+				return 0;
+		}
+	}
+	return -ENOTCONN;
+}
+
+
+#define DBGP_DEBUG 0
+#if DBGP_DEBUG
+void early_printk(const char *fmt, ...);
+# define dbgp_printk early_printk
+#else
+static inline void dbgp_printk(const char *fmt, ...) { }
+#endif
+
+static int ehci_setup(void)
+{
+	unsigned cmd, ctrl, status, portsc, hcs_params, debug_port, n_ports;
+	int ret;
+	int i;
+
+	hcs_params = readl(&ehci_caps->hcs_params);
+	debug_port = HCS_DEBUG_PORT(hcs_params);
+	n_ports    = HCS_N_PORTS(hcs_params);
+
+	dbgp_printk("debug_port: %d\n", debug_port);
+	dbgp_printk("n_ports:    %d\n", n_ports);
+
+	/* Reset the EHCI controller */
+	cmd = readl(&ehci_regs->command);
+	cmd |=CMD_RESET;
+	writel(cmd, &ehci_regs->command);
+	while (cmd & CMD_RESET)
+		cmd = readl(&ehci_regs->command);
+
+	/* Claim ownership, but do not enable yet */
+	ctrl = readl(&ehci_debug->control);
+	ctrl |= DBGP_OWNER;
+	ctrl &= ~(DBGP_ENABLED | DBGP_INUSE);
+	writel(ctrl, &ehci_debug->control);
+
+	/* Start the ehci running */
+	cmd = readl(&ehci_regs->command);
+	cmd &= ~(CMD_LRESET | CMD_IAAD | CMD_PSE | CMD_ASE | CMD_RESET);
+	cmd |= CMD_RUN;
+	writel(cmd, &ehci_regs->command);
+
+	/* Ensure everything is routed to the EHCI */
+	writel(FLAG_CF, &ehci_regs->configured_flag);
+
+	/* Wait until the controller is no longer halted */
+	do {
+		status = readl(&ehci_regs->status);
+	} while (status & STS_HALT);
+
+	/* Wait for a device to show up in the debug port */
+	ret = ehci_wait_for_port(debug_port);
+	if (ret < 0) {
+		dbgp_printk("No device found in debug port\n");
+		return -1;
+	}
+
+	/* Enable the debug port */
+	ctrl = readl(&ehci_debug->control);
+	ctrl |= DBGP_CLAIM;
+	writel(ctrl, &ehci_debug->control);
+	ctrl = readl(&ehci_debug->control);
+	if ((ctrl & DBGP_CLAIM) != DBGP_CLAIM) {
+		dbgp_printk("No device in debug port\n");
+		writel(ctrl & ~DBGP_CLAIM, &ehci_debug->control);
+		return -1;
+
+	}
+
+	/* Completely transfer the debug device to the debug controller */
+	portsc = readl(&ehci_regs->port_status[debug_port - 1]);
+	portsc &= ~PORT_PE;
+	writel(portsc, &ehci_regs->port_status[debug_port - 1]);
+
+	return 0;
+}
+
+static __init void early_dbgp_init(char *s)
+{
+	struct usb_debug_descriptor dbgp_desc;
+	void __iomem *ehci_bar;
+	unsigned ctrl, devnum;
+	unsigned bus, slot, func, cap;
+	unsigned debug_port, bar, offset;
+	unsigned bar_val;
+	unsigned dbgp_num;
+	char *e;
+	int ret;
+
+	if (!early_pci_allowed())
+		return;
+
+	dbgp_num = 0;
+	if (*s) {
+		dbgp_num = simple_strtoul(s, &e, 10);
+	}
+	dbgp_printk("dbgp_num: %d\n", dbgp_num);
+	cap = find_dbgp(dbgp_num, &bus, &slot, &func);
+	if (!cap)
+		return;
+
+	dbgp_printk("Found EHCI debug port\n");
+
+	debug_port = read_pci_config(bus, slot, func, cap);
+	bar = (debug_port >> 29) & 0x7;
+	bar = (bar * 4) + 0xc;
+	offset = (debug_port >> 16) & 0xfff;
+	if (bar != PCI_BASE_ADDRESS_0) {
+		dbgp_printk("only debug ports on bar 1 handled.\n");
+		return;
+	}
+
+	/* FIXME this assumes the bar is a 32bit mmio bar */
+	bar_val = read_pci_config(bus, slot, func, PCI_BASE_ADDRESS_0);
+
+	/* FIXME I don't have the bar size so just guess PAGE_SIZE is more
+	 * than enough.  1K is the biggest I have seen.
+	 */
+	set_fixmap_nocache(FIX_DBGP_BASE, bar_val & PAGE_MASK);
+	ehci_bar = (void __iomem *)__fix_to_virt(FIX_DBGP_BASE);
+	ehci_bar += bar_val & ~PAGE_MASK;
+
+	ehci_caps  = ehci_bar;
+	ehci_regs  = ehci_bar + HC_LENGTH(readl(&ehci_caps->hc_capbase));
+	ehci_debug = ehci_bar + offset;
+
+	ret = ehci_setup();
+	if (ret < 0) {
+		dbgp_printk("ehci_setup failed\n");
+		return;
+	}
+
+	/* Find the debug device and make it device number 127 */
+	for (devnum = 0; devnum <= 127; devnum++) {
+		ret = dbgp_control_msg(devnum,
+			USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+			USB_REQ_GET_DESCRIPTOR, (USB_DT_DEBUG << 8), 0,
+			&dbgp_desc, sizeof(dbgp_desc));
+		if (ret > 0)
+			break;
+	}
+	if (devnum > 127) {
+		dbgp_printk("Could not find attached debug device\n");
+		goto err;
+	}
+	if (ret < 0) {
+		dbgp_printk("Attached device is not a debug device\n");
+		goto err;
+	}
+	dbgp_endpoint_out = dbgp_desc.bDebugOutEndpoint;
+
+	/* Move the device to 127 if it isn't already there */
+	if (devnum != USB_DEBUG_DEVNUM) {
+		ret = dbgp_control_msg(devnum,
+			USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+			USB_REQ_SET_ADDRESS, USB_DEBUG_DEVNUM, 0, NULL, 0);
+		if (ret < 0) {
+			dbgp_printk("Could not move attached device to %d\n", 
+				USB_DEBUG_DEVNUM);
+			goto err;
+		}
+		devnum = USB_DEBUG_DEVNUM;
+	}
+
+	/* Enable the debug interface */
+	ret = dbgp_control_msg(USB_DEBUG_DEVNUM,
+		USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+		USB_REQ_SET_FEATURE, USB_DEVICE_DEBUG_MODE, 0, NULL, 0);
+	if (ret < 0) {
+		dbgp_printk(" Could not enable the debug device\n");
+		goto err;
+	}
+
+	/* Perform a small write to get the even/odd data state in sync
+	 */
+	ret = dbgp_bulk_write(USB_DEBUG_DEVNUM, dbgp_endpoint_out, " ",1);
+	if (ret < 0) {
+		dbgp_printk("dbgp_bulk_write failed: %d\n", ret);
+		goto err;
+	}
+
+
+	return;
+err:
+	/* Things didn't work so remove my claim */
+	ctrl = readl(&ehci_debug->control);
+	ctrl &= ~(DBGP_CLAIM | DBGP_OUT);
+	writel(ctrl, &ehci_debug->control);
+	return;
+}
+
+static void early_dbgp_write(struct console *con, const char *str, unsigned n)
+{
+	int chunk, ret;
+	if (!ehci_debug)
+		return;
+	while (n > 0) {
+		chunk = n;
+		if (chunk > DBGP_MAX_PACKET)
+			chunk = DBGP_MAX_PACKET;
+		ret = dbgp_bulk_write(USB_DEBUG_DEVNUM, 
+			dbgp_endpoint_out, str, chunk);
+		str += chunk;
+		n -= chunk;
+	}
+}
+
+static struct console early_dbgp_console = {
+	.name =		"earlydbg",
+	.write =	early_dbgp_write,
+	.flags = 	CON_PRINTBUFFER,
+	.index = 	-1,
+};
+
+#endif
+
 /* Console interface to a host file on AMD's SimNow! */
 
 static int simnow_fd;
@@ -242,8 +804,20 @@ static int __init setup_early_printk(cha
  		simnow_init(buf + 6);
  		early_console = &simnow_console;
  		keep_early = 1;
+	} else if (!strncmp(buf, "dbgp", 4)) {
+		early_dbgp_init(buf + 4);
+		early_console = &early_dbgp_console;
 	}
 	register_console(early_console);
+#if DBGP_DEBUG
+	{
+		static const char dbgp_test_str[] = 
+			"The quick brown fox jumped over the lazy dog!\n";
+		early_dbgp_init("");
+		early_dbgp_write(&early_dbgp_console, 
+			dbgp_test_str, sizeof(dbgp_test_str) - 1);
+	}
+#endif
 	return 0;
 }
 
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index bbc3082..0a67192 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -46,6 +46,7 @@ struct ehci_stats {
 
 #define	EHCI_MAX_ROOT_PORTS	15		/* see HCS_N_PORTS */
 
+#ifndef EARLY_PRINTK
 struct ehci_hcd {			/* one per controller */
 	/* glue to PCI and HCD framework */
 	struct ehci_caps __iomem *caps;
@@ -160,6 +161,7 @@ timer_action (struct ehci_hcd *ehci, enu
 		mod_timer (&ehci->watchdog, t);
 	}
 }
+#endif /* EARLY_PRINTK */
 
 /*-------------------------------------------------------------------------*/
 
@@ -384,6 +386,7 @@ union ehci_shadow {
  * These appear in both the async and (for interrupt) periodic schedules.
  */
 
+#ifndef EARLY_PRINTK
 struct ehci_qh {
 	/* first part defined by EHCI spec */
 	__le32			hw_next;	 /* see EHCI 3.6.1 */
@@ -432,6 +435,7 @@ #define	QH_STATE_COMPLETING	5		/* don't 
 #define NO_FRAME ((unsigned short)~0)			/* pick new start */
 	struct usb_device	*dev;		/* access to TT */
 } __attribute__ ((aligned (32)));
+#endif /* EARLY_PRITNK */
 
 /*-------------------------------------------------------------------------*/
 
@@ -601,6 +605,8 @@ struct ehci_fstn {
 	union ehci_shadow	fstn_next;	/* ptr to periodic q entry */
 } __attribute__ ((aligned (32)));
 
+#ifndef EARLY_PRINTK
+
 /*-------------------------------------------------------------------------*/
 
 #ifdef CONFIG_USB_EHCI_ROOT_HUB_TT
@@ -659,4 +665,6 @@ #endif	/* DEBUG */
 
 /*-------------------------------------------------------------------------*/
 
+#endif /* EARLY_PRINTK */
+
 #endif /* __LINUX_EHCI_HCD_H */
diff --git a/include/asm-x86_64/fixmap.h b/include/asm-x86_64/fixmap.h
index 1b620db..1f2978a 100644
--- a/include/asm-x86_64/fixmap.h
+++ b/include/asm-x86_64/fixmap.h
@@ -36,6 +36,7 @@ enum fixed_addresses {
 	VSYSCALL_LAST_PAGE,
 	VSYSCALL_FIRST_PAGE = VSYSCALL_LAST_PAGE + ((VSYSCALL_END-VSYSCALL_START) >> PAGE_SHIFT) - 1,
 	VSYSCALL_HPET,
+	FIX_DBGP_BASE,
 	FIX_HPET_BASE,
 	FIX_APIC_BASE,	/* local (CPU) APIC) -- required for SMP or not */
 	FIX_IO_APIC_BASE_0,
-- 
1.4.2.rc3.g7e18e-dirty


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* Re: [linux-usb-devel] [RFC][PATCH 0/2] x86_64 Early usb debug port support.
       [not found]       ` <200612042001.09808.david-b@pacbell.net>
@ 2006-12-05 11:01         ` Eric W. Biederman
  2006-12-06 17:31           ` Andi Kleen
  2006-12-05 11:18         ` Eric W. Biederman
  1 sibling, 1 reply; 29+ messages in thread
From: Eric W. Biederman @ 2006-12-05 11:01 UTC (permalink / raw)
  To: David Brownell
  Cc: linux-usb-devel, Peter Stuge, Stefan Reinauer, Greg KH,
	linux-kernel, Lu, Yinghai, Andi Kleen, linuxbios


Ok due to popular demands here is the slightly fixed patch that works
on both i386 and x86_64.  For the i386 version you must not have
HIGHMEM64G enabled. 

I just rolled it all into one patch as I'm to lazy to transmit all
3 of them.

Eric

 arch/i386/kernel/head.S           |    8 +
 arch/x86_64/kernel/early_printk.c |  580 +++++++++++++++++++++++++++++++++++++
 arch/x86_64/kernel/head.S         |   11 +-
 drivers/usb/host/ehci.h           |    8 +
 include/asm-i386/fixmap.h         |    1 +
 include/asm-x86_64/fixmap.h       |    1 +
 6 files changed, 608 insertions(+), 1 deletions(-)

diff --git a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S
index ca31f18..f683565 100644
--- a/arch/i386/kernel/head.S
+++ b/arch/i386/kernel/head.S
@@ -135,6 +135,12 @@ page_pde_offset = (__PAGE_OFFSET >> 20);
 	jb 10b
 	movl %edi,(init_pg_tables_end - __PAGE_OFFSET)
 
+	/* Do an early initialization of the fixmap area */
+	movl $(swapper_pg_dir - __PAGE_OFFSET), %edx
+	movl $(swapper_pg_pmd - __PAGE_OFFSET), %eax
+	addl $0x007, %eax			/* 0x007 = PRESENT+RW+USER */
+	movl %eax, 4092(%edx)
+
 #ifdef CONFIG_SMP
 	xorl %ebx,%ebx				/* This is the boot CPU (BSP) */
 	jmp 3f
@@ -477,6 +483,8 @@ ENTRY(_stext)
 .section ".bss.page_aligned","w"
 ENTRY(swapper_pg_dir)
 	.fill 1024,4,0
+ENTRY(swapper_pg_pmd)
+	.fill 1024,4,0	
 ENTRY(empty_zero_page)
 	.fill 4096,1,0
 
diff --git a/arch/x86_64/kernel/early_printk.c b/arch/x86_64/kernel/early_printk.c
index d4050a5..71f2f88 100644
--- a/arch/x86_64/kernel/early_printk.c
+++ b/arch/x86_64/kernel/early_printk.c
@@ -3,9 +3,19 @@
 #include <linux/init.h>
 #include <linux/string.h>
 #include <linux/screen_info.h>
+#include <linux/usb_ch9.h>
+#include <linux/pci_regs.h>
+#include <linux/pci_ids.h>
+#include <linux/errno.h>
 #include <asm/io.h>
 #include <asm/processor.h>
 #include <asm/fcntl.h>
+#include <asm/pci-direct.h>
+#include <asm/pgtable.h>
+#include <asm/fixmap.h>
+#define EARLY_PRINTK
+#include "../../../drivers/usb/host/ehci.h"
+
 
 /* Simple VGA output */
 
@@ -155,6 +165,564 @@ static struct console early_serial_console = {
 	.index =	-1,
 };
 
+
+static struct ehci_caps __iomem *ehci_caps;
+static struct ehci_regs __iomem *ehci_regs;
+static struct ehci_dbg_port __iomem *ehci_debug;
+static unsigned dbgp_endpoint_out;
+
+#define USB_DEBUG_DEVNUM 127
+
+#define DBGP_DATA_TOGGLE	0x8800
+#define DBGP_PID_UPDATE(x, tok) \
+	((((x) ^ DBGP_DATA_TOGGLE) & 0xffff00) | ((tok) & 0xff))
+
+#define DBGP_LEN_UPDATE(x, len) (((x) & ~0x0f) | ((len) & 0x0f))
+/*
+ * USB Packet IDs (PIDs)
+ */
+
+/* token */
+#define USB_PID_OUT		0xe1
+#define USB_PID_IN		0x69
+#define USB_PID_SOF		0xa5
+#define USB_PID_SETUP		0x2d
+/* handshake */
+#define USB_PID_ACK		0xd2
+#define USB_PID_NAK		0x5a
+#define USB_PID_STALL		0x1e
+#define USB_PID_NYET		0x96
+/* data */
+#define USB_PID_DATA0		0xc3
+#define USB_PID_DATA1		0x4b
+#define USB_PID_DATA2		0x87
+#define USB_PID_MDATA		0x0f
+/* Special */
+#define USB_PID_PREAMBLE	0x3c
+#define USB_PID_ERR		0x3c
+#define USB_PID_SPLIT		0x78
+#define USB_PID_PING		0xb4
+#define USB_PID_UNDEF_0		0xf0
+
+#define USB_PID_DATA_TOGGLE	0x88
+#define DBGP_CLAIM (DBGP_OWNER | DBGP_ENABLED | DBGP_INUSE)
+
+#define PCI_CAP_ID_EHCI_DEBUG	0xa
+
+#define HUB_ROOT_RESET_TIME	50	/* times are in msec */
+#define HUB_SHORT_RESET_TIME	10
+#define HUB_LONG_RESET_TIME	200
+#define HUB_RESET_TIMEOUT	500
+
+#define DBGP_MAX_PACKET		8
+
+static int dbgp_wait_until_complete(void)
+{
+	unsigned ctrl;
+	for (;;) {
+		ctrl = readl(&ehci_debug->control);
+		/* Stop when the transaction is finished */
+		if (ctrl & DBGP_DONE)
+			break;
+	}
+	/* Now that we have observed the completed transaction,
+	 * clear the done bit.
+	 */
+	writel(ctrl | DBGP_DONE, &ehci_debug->control);
+	return (ctrl & DBGP_ERROR) ? -DBGP_ERRCODE(ctrl) : DBGP_LEN(ctrl);
+}
+
+static void dbgp_mdelay(int ms)
+{
+	int i;
+	while (ms--) {
+		for (i = 0; i < 1000; i++)
+			outb(0x1, 0x80);
+	}
+}
+
+static void dbgp_breath(void)
+{
+	/* Sleep to give the debug port a chance to breathe */
+}
+
+static int dbgp_wait_until_done(unsigned ctrl)
+{
+	unsigned pids, lpid;
+	int ret;
+
+retry:
+	writel(ctrl | DBGP_GO, &ehci_debug->control);
+	ret = dbgp_wait_until_complete();
+	pids = readl(&ehci_debug->pids);
+	lpid = DBGP_PID_GET(pids);
+
+	if (ret < 0)
+		return ret;
+
+	/* If the port is getting full or it has dropped data
+	 * start pacing ourselves, not necessary but it's friendly.
+	 */
+	if ((lpid == USB_PID_NAK) || (lpid == USB_PID_NYET))
+		dbgp_breath();
+	
+	/* If I get a NACK reissue the transmission */
+	if (lpid == USB_PID_NAK)
+		goto retry;
+
+	return ret;
+}
+
+static void dbgp_set_data(const void *buf, int size)
+{
+	const unsigned char *bytes = buf;
+	unsigned lo, hi;
+	int i;
+	lo = hi = 0;
+	for (i = 0; i < 4 && i < size; i++)
+		lo |= bytes[i] << (8*i);
+	for (; i < 8 && i < size; i++)
+		hi |= bytes[i] << (8*(i - 4));
+	writel(lo, &ehci_debug->data03);
+	writel(hi, &ehci_debug->data47);
+}
+
+static void dbgp_get_data(void *buf, int size)
+{
+	unsigned char *bytes = buf;
+	unsigned lo, hi;
+	int i;
+	lo = readl(&ehci_debug->data03);
+	hi = readl(&ehci_debug->data47);
+	for (i = 0; i < 4 && i < size; i++)
+		bytes[i] = (lo >> (8*i)) & 0xff;
+	for (; i < 8 && i < size; i++)
+		bytes[i] = (hi >> (8*(i - 4))) & 0xff;
+}
+
+static int dbgp_bulk_write(unsigned devnum, unsigned endpoint, const char *bytes, int size)
+{
+	unsigned pids, addr, ctrl;
+	int ret;
+	if (size > DBGP_MAX_PACKET)
+		return -1;
+
+	addr = DBGP_EPADDR(devnum, endpoint);
+
+	pids = readl(&ehci_debug->pids);
+	pids = DBGP_PID_UPDATE(pids, USB_PID_OUT);
+	
+	ctrl = readl(&ehci_debug->control);
+	ctrl = DBGP_LEN_UPDATE(ctrl, size);
+	ctrl |= DBGP_OUT;
+	ctrl |= DBGP_GO;
+
+	dbgp_set_data(bytes, size);
+	writel(addr, &ehci_debug->address);
+	writel(pids, &ehci_debug->pids);
+
+	ret = dbgp_wait_until_done(ctrl);
+	if (ret < 0) {
+		return ret;
+	}
+	return ret;
+}
+
+static int dbgp_bulk_read(unsigned devnum, unsigned endpoint, void *data, int size)
+{
+	unsigned pids, addr, ctrl;
+	int ret;
+
+	if (size > DBGP_MAX_PACKET)
+		return -1;
+
+	addr = DBGP_EPADDR(devnum, endpoint);
+
+	pids = readl(&ehci_debug->pids);
+	pids = DBGP_PID_UPDATE(pids, USB_PID_IN);
+		
+	ctrl = readl(&ehci_debug->control);
+	ctrl = DBGP_LEN_UPDATE(ctrl, size);
+	ctrl &= ~DBGP_OUT;
+	ctrl |= DBGP_GO;
+		
+	writel(addr, &ehci_debug->address);
+	writel(pids, &ehci_debug->pids);
+	ret = dbgp_wait_until_done(ctrl);
+	if (ret < 0)
+		return ret;
+	if (size > ret)
+		size = ret;
+	dbgp_get_data(data, size);
+	return ret;
+}
+
+static int dbgp_control_msg(unsigned devnum, int requesttype, int request, 
+	int value, int index, void *data, int size)
+{
+	unsigned pids, addr, ctrl;
+	struct usb_ctrlrequest req;
+	int read;
+	int ret;
+
+	read = (requesttype & USB_DIR_IN) != 0;
+	if (size > (read?DBGP_MAX_PACKET:0))
+		return -1;
+	
+	/* Compute the control message */
+	req.bRequestType = requesttype;
+	req.bRequest = request;
+	req.wValue = value;
+	req.wIndex = index;
+	req.wLength = size;
+
+	pids = DBGP_PID_SET(USB_PID_DATA0, USB_PID_SETUP);
+	addr = DBGP_EPADDR(devnum, 0);
+
+	ctrl = readl(&ehci_debug->control);
+	ctrl = DBGP_LEN_UPDATE(ctrl, sizeof(req));
+	ctrl |= DBGP_OUT;
+	ctrl |= DBGP_GO;
+
+	/* Send the setup message */
+	dbgp_set_data(&req, sizeof(req));
+	writel(addr, &ehci_debug->address);
+	writel(pids, &ehci_debug->pids);
+	ret = dbgp_wait_until_done(ctrl);
+	if (ret < 0)
+		return ret;
+
+
+	/* Read the result */
+	ret = dbgp_bulk_read(devnum, 0, data, size);
+	return ret;
+}
+
+
+/* Find a PCI capability */
+static __u32 __init find_cap(int num, int slot, int func, int cap) 
+{ 
+	u8 pos;
+	int bytes;
+	if (!(read_pci_config_16(num,slot,func,PCI_STATUS) & PCI_STATUS_CAP_LIST))
+		return 0;
+	pos = read_pci_config_byte(num,slot,func,PCI_CAPABILITY_LIST);
+	for (bytes = 0; bytes < 48 && pos >= 0x40; bytes++) { 
+		u8 id;
+		pos &= ~3; 
+		id = read_pci_config_byte(num,slot,func,pos+PCI_CAP_LIST_ID);
+		if (id == 0xff)
+			break;
+		if (id == cap) 
+			return pos; 
+		pos = read_pci_config_byte(num,slot,func,pos+PCI_CAP_LIST_NEXT); 
+	} 
+	return 0;
+} 
+
+static __u32 __init find_dbgp(int ehci_num, unsigned *rbus, unsigned *rslot, unsigned *rfunc)
+{
+	unsigned bus, slot, func;
+	
+	for (bus = 0; bus < 256; bus++) {
+		for (slot = 0; slot < 32; slot++) {
+			for (func = 0; func < 8; func++) {
+				u32 class;
+				unsigned cap;
+				class = read_pci_config(bus, slot, func, PCI_CLASS_REVISION);
+				if ((class >> 8) != PCI_CLASS_SERIAL_USB_EHCI)
+					continue;
+				cap = find_cap(bus, slot, func, PCI_CAP_ID_EHCI_DEBUG);
+				if (!cap)
+					continue;
+				if (ehci_num-- != 0)
+					continue;
+				*rbus = bus;
+				*rslot = slot;
+				*rfunc = func;
+				return cap;
+			}
+		}
+	}
+	return 0;
+}
+
+static int ehci_reset_port(int port)
+{
+	unsigned portsc;
+	unsigned delay_time, delay;
+
+	/* Reset the usb debug port */
+	portsc = readl(&ehci_regs->port_status[port - 1]);
+	portsc &= ~PORT_PE;
+	portsc |= PORT_RESET;
+	writel(portsc, &ehci_regs->port_status[port - 1]);
+
+	delay = HUB_ROOT_RESET_TIME;
+	for (delay_time = 0; delay_time < HUB_RESET_TIMEOUT;
+	     delay_time += delay) {
+		dbgp_mdelay(delay);
+
+		portsc = readl(&ehci_regs->port_status[port - 1]);
+		if (portsc & PORT_RESET) {
+			/* force reset to complete */
+			writel(portsc & ~(PORT_RWC_BITS | PORT_RESET), 
+				&ehci_regs->port_status[port - 1]);
+			while (portsc & PORT_RESET)
+				portsc = readl(&ehci_regs->port_status[port - 1]);
+		}
+
+		/* Device went away? */
+		if (!(portsc & PORT_CONNECT))
+			return -ENOTCONN;
+
+		/* bomb out completely if something weird happend */
+		if ((portsc & PORT_CSC))
+			return -EINVAL;
+
+		/* If we've finished resetting, then break out of the loop */
+		if (!(portsc & PORT_RESET) && (portsc & PORT_PE))
+			return 0;
+	}
+	return -EBUSY;
+}
+
+static int ehci_wait_for_port(int port)
+{
+	unsigned status;
+	int ret, reps;
+	for (reps = 0; reps >= 0; reps++) {
+		status = readl(&ehci_regs->status);
+		if (status & STS_PCD) {
+			ret = ehci_reset_port(port);
+			if (ret == 0)
+				return 0;
+		}
+	}
+	return -ENOTCONN;
+}
+
+
+#define DBGP_DEBUG 0
+#if DBGP_DEBUG
+void early_printk(const char *fmt, ...);
+# define dbgp_printk early_printk
+#else
+static inline void dbgp_printk(const char *fmt, ...) { }
+#endif
+
+static int ehci_setup(void)
+{
+	unsigned cmd, ctrl, status, portsc, hcs_params, debug_port, n_ports;
+	int ret;
+
+	hcs_params = readl(&ehci_caps->hcs_params);
+	debug_port = HCS_DEBUG_PORT(hcs_params);
+	n_ports    = HCS_N_PORTS(hcs_params);
+
+	dbgp_printk("debug_port: %d\n", debug_port);
+	dbgp_printk("n_ports:    %d\n", n_ports);
+
+	/* Reset the EHCI controller */
+	cmd = readl(&ehci_regs->command);
+	cmd |=CMD_RESET;
+	writel(cmd, &ehci_regs->command);
+	while (cmd & CMD_RESET)
+		cmd = readl(&ehci_regs->command);
+
+	/* Claim ownership, but do not enable yet */
+	ctrl = readl(&ehci_debug->control);
+	ctrl |= DBGP_OWNER;
+	ctrl &= ~(DBGP_ENABLED | DBGP_INUSE);
+	writel(ctrl, &ehci_debug->control);
+
+	/* Start the ehci running */
+	cmd = readl(&ehci_regs->command);
+	cmd &= ~(CMD_LRESET | CMD_IAAD | CMD_PSE | CMD_ASE | CMD_RESET);
+	cmd |= CMD_RUN;
+	writel(cmd, &ehci_regs->command);
+
+	/* Ensure everything is routed to the EHCI */
+	writel(FLAG_CF, &ehci_regs->configured_flag);
+
+	/* Wait until the controller is no longer halted */
+	do {
+		status = readl(&ehci_regs->status);
+	} while (status & STS_HALT);
+
+	/* Wait for a device to show up in the debug port */
+	ret = ehci_wait_for_port(debug_port);
+	if (ret < 0) {
+		dbgp_printk("No device found in debug port\n");
+		return -1;
+	}
+
+	/* Enable the debug port */
+	ctrl = readl(&ehci_debug->control);
+	ctrl |= DBGP_CLAIM;
+	writel(ctrl, &ehci_debug->control);
+	ctrl = readl(&ehci_debug->control);
+	if ((ctrl & DBGP_CLAIM) != DBGP_CLAIM) {
+		dbgp_printk("No device in debug port\n");
+		writel(ctrl & ~DBGP_CLAIM, &ehci_debug->control);
+		return -1;
+
+	}
+
+	/* Completely transfer the debug device to the debug controller */
+	portsc = readl(&ehci_regs->port_status[debug_port - 1]);
+	portsc &= ~PORT_PE;
+	writel(portsc, &ehci_regs->port_status[debug_port - 1]);
+
+	return 0;
+}
+
+static __init void early_dbgp_init(char *s)
+{
+	struct usb_debug_descriptor dbgp_desc;
+	void __iomem *ehci_bar;
+	unsigned ctrl, devnum;
+	unsigned bus, slot, func, cap;
+	unsigned debug_port, bar, offset;
+	unsigned bar_val;
+	unsigned dbgp_num;
+	char *e;
+	int ret;
+
+	if (!early_pci_allowed())
+		return;
+
+	dbgp_num = 0;
+	if (*s) {
+		dbgp_num = simple_strtoul(s, &e, 10);
+	}
+	dbgp_printk("dbgp_num: %d\n", dbgp_num);
+	cap = find_dbgp(dbgp_num, &bus, &slot, &func);
+	if (!cap)
+		return;
+
+	dbgp_printk("Found EHCI debug port\n");
+
+	debug_port = read_pci_config(bus, slot, func, cap);
+	bar = (debug_port >> 29) & 0x7;
+	bar = (bar * 4) + 0xc;
+	offset = (debug_port >> 16) & 0xfff;
+	dbgp_printk("bar: %02x offset: %03x\n", bar, offset);
+	if (bar != PCI_BASE_ADDRESS_0) {
+		dbgp_printk("only debug ports on bar 1 handled.\n");
+		return;
+	}
+
+	bar_val = read_pci_config(bus, slot, func, PCI_BASE_ADDRESS_0);
+	dbgp_printk("bar: %02x offset: %03x\n", bar, offset);
+	if (bar_val & ~PCI_BASE_ADDRESS_MEM_MASK) {
+		dbgp_printk("only simple 32bit mmio bars supported\n");
+		return;
+	}
+		
+
+	/* FIXME I don't have the bar size so just guess PAGE_SIZE is more
+	 * than enough.  1K is the biggest I have seen.
+	 */
+	dbgp_printk("dbgp pre-set_fixmap_nocache\n");
+	set_fixmap_nocache(FIX_DBGP_BASE, bar_val & PAGE_MASK);
+	dbgp_printk("dbgp post-set_fixmap_nocache\n");
+	ehci_bar = (void __iomem *)__fix_to_virt(FIX_DBGP_BASE);
+	ehci_bar += bar_val & ~PAGE_MASK;
+	dbgp_printk("ehci_bar: %p\n", ehci_bar);
+
+	ehci_caps  = ehci_bar;
+	ehci_regs  = ehci_bar + HC_LENGTH(readl(&ehci_caps->hc_capbase));
+	ehci_debug = ehci_bar + offset;
+
+	ret = ehci_setup();
+	if (ret < 0) {
+		dbgp_printk("ehci_setup failed\n");
+		return;
+	}
+
+	/* Find the debug device and make it device number 127 */
+	for (devnum = 0; devnum <= 127; devnum++) {
+		ret = dbgp_control_msg(devnum,
+			USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+			USB_REQ_GET_DESCRIPTOR, (USB_DT_DEBUG << 8), 0,
+			&dbgp_desc, sizeof(dbgp_desc));
+		if (ret > 0)
+			break;
+	}
+	if (devnum > 127) {
+		dbgp_printk("Could not find attached debug device\n");
+		goto err;
+	}
+	if (ret < 0) {
+		dbgp_printk("Attached device is not a debug device\n");
+		goto err;
+	}
+	dbgp_endpoint_out = dbgp_desc.bDebugOutEndpoint;
+
+	/* Move the device to 127 if it isn't already there */
+	if (devnum != USB_DEBUG_DEVNUM) {
+		ret = dbgp_control_msg(devnum,
+			USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+			USB_REQ_SET_ADDRESS, USB_DEBUG_DEVNUM, 0, NULL, 0);
+		if (ret < 0) {
+			dbgp_printk("Could not move attached device to %d\n", 
+				USB_DEBUG_DEVNUM);
+			goto err;
+		}
+		devnum = USB_DEBUG_DEVNUM;
+	}
+
+	/* Enable the debug interface */
+	ret = dbgp_control_msg(USB_DEBUG_DEVNUM,
+		USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+		USB_REQ_SET_FEATURE, USB_DEVICE_DEBUG_MODE, 0, NULL, 0);
+	if (ret < 0) {
+		dbgp_printk(" Could not enable the debug device\n");
+		goto err;
+	}
+
+	/* Perform a small write to get the even/odd data state in sync
+	 */
+	ret = dbgp_bulk_write(USB_DEBUG_DEVNUM, dbgp_endpoint_out, " ",1);
+	if (ret < 0) {
+		dbgp_printk("dbgp_bulk_write failed: %d\n", ret);
+		goto err;
+	}
+
+
+	return;
+err:
+	/* Things didn't work so remove my claim */
+	ctrl = readl(&ehci_debug->control);
+	ctrl &= ~(DBGP_CLAIM | DBGP_OUT);
+	writel(ctrl, &ehci_debug->control);
+	return;
+}
+
+static void early_dbgp_write(struct console *con, const char *str, unsigned n)
+{
+	int chunk, ret;
+	if (!ehci_debug)
+		return;
+	while (n > 0) {
+		chunk = n;
+		if (chunk > DBGP_MAX_PACKET)
+			chunk = DBGP_MAX_PACKET;
+		ret = dbgp_bulk_write(USB_DEBUG_DEVNUM, 
+			dbgp_endpoint_out, str, chunk);
+		str += chunk;
+		n -= chunk;
+	}
+}
+
+static struct console early_dbgp_console = {
+	.name =		"earlydbg",
+	.write =	early_dbgp_write,
+	.flags = 	CON_PRINTBUFFER,
+	.index = 	-1,
+};
+
 /* Console interface to a host file on AMD's SimNow! */
 
 static int simnow_fd;
@@ -242,8 +810,20 @@ static int __init setup_early_printk(char *buf)
  		simnow_init(buf + 6);
  		early_console = &simnow_console;
  		keep_early = 1;
+	} else if (!strncmp(buf, "dbgp", 4)) {
+		early_dbgp_init(buf + 4);
+		early_console = &early_dbgp_console;
 	}
 	register_console(early_console);
+#if DBGP_DEBUG
+	{
+		static const char dbgp_test_str[] = 
+			"The quick brown fox jumped over the lazy dog!\n";
+		early_dbgp_init("");
+		early_dbgp_write(&early_dbgp_console, 
+			dbgp_test_str, sizeof(dbgp_test_str) - 1);
+	}
+#endif
 	return 0;
 }
 
diff --git a/arch/x86_64/kernel/head.S b/arch/x86_64/kernel/head.S
index 2f65469..4004965 100644
--- a/arch/x86_64/kernel/head.S
+++ b/arch/x86_64/kernel/head.S
@@ -271,7 +271,16 @@ NEXT_PAGE(level3_kernel_pgt)
 	.fill	510,8,0
 	/* (2^48-(2*1024*1024*1024)-((2^39)*511))/(2^30) = 510 */
 	.quad	phys_level2_kernel_pgt | 0x007
-	.fill	1,8,0
+	.quad	phys_level2_fixmap_pgt | 0x007
+
+NEXT_PAGE(level2_fixmap_pgt)
+	.fill	506,8,0
+	.quad	phys_level1_fixmap_pgt | 0x007
+	/* 8MB reserved for vsyscalls + a 2MB hole = 4 + 1 entries */
+	.fill	5,8,0
+
+NEXT_PAGE(level1_fixmap_pgt)
+	.fill	512,8,0
 
 NEXT_PAGE(level2_ident_pgt)
 	/* 40MB for bootup. 	*/
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index bbc3082..0a67192 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -46,6 +46,7 @@ struct ehci_stats {
 
 #define	EHCI_MAX_ROOT_PORTS	15		/* see HCS_N_PORTS */
 
+#ifndef EARLY_PRINTK
 struct ehci_hcd {			/* one per controller */
 	/* glue to PCI and HCD framework */
 	struct ehci_caps __iomem *caps;
@@ -160,6 +161,7 @@ timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action)
 		mod_timer (&ehci->watchdog, t);
 	}
 }
+#endif /* EARLY_PRINTK */
 
 /*-------------------------------------------------------------------------*/
 
@@ -384,6 +386,7 @@ union ehci_shadow {
  * These appear in both the async and (for interrupt) periodic schedules.
  */
 
+#ifndef EARLY_PRINTK
 struct ehci_qh {
 	/* first part defined by EHCI spec */
 	__le32			hw_next;	 /* see EHCI 3.6.1 */
@@ -432,6 +435,7 @@ struct ehci_qh {
 #define NO_FRAME ((unsigned short)~0)			/* pick new start */
 	struct usb_device	*dev;		/* access to TT */
 } __attribute__ ((aligned (32)));
+#endif /* EARLY_PRITNK */
 
 /*-------------------------------------------------------------------------*/
 
@@ -601,6 +605,8 @@ struct ehci_fstn {
 	union ehci_shadow	fstn_next;	/* ptr to periodic q entry */
 } __attribute__ ((aligned (32)));
 
+#ifndef EARLY_PRINTK
+
 /*-------------------------------------------------------------------------*/
 
 #ifdef CONFIG_USB_EHCI_ROOT_HUB_TT
@@ -659,4 +665,6 @@ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
 
 /*-------------------------------------------------------------------------*/
 
+#endif /* EARLY_PRINTK */
+
 #endif /* __LINUX_EHCI_HCD_H */
diff --git a/include/asm-i386/fixmap.h b/include/asm-i386/fixmap.h
index 02428cb..ea08885 100644
--- a/include/asm-i386/fixmap.h
+++ b/include/asm-i386/fixmap.h
@@ -56,6 +56,7 @@ extern unsigned long __FIXADDR_TOP;
 enum fixed_addresses {
 	FIX_HOLE,
 	FIX_VDSO,
+	FIX_DBGP_BASE,
 #ifdef CONFIG_X86_LOCAL_APIC
 	FIX_APIC_BASE,	/* local (CPU) APIC) -- required for SMP or not */
 #endif
diff --git a/include/asm-x86_64/fixmap.h b/include/asm-x86_64/fixmap.h
index 1b620db..1f2978a 100644
--- a/include/asm-x86_64/fixmap.h
+++ b/include/asm-x86_64/fixmap.h
@@ -36,6 +36,7 @@ enum fixed_addresses {
 	VSYSCALL_LAST_PAGE,
 	VSYSCALL_FIRST_PAGE = VSYSCALL_LAST_PAGE + ((VSYSCALL_END-VSYSCALL_START) >> PAGE_SHIFT) - 1,
 	VSYSCALL_HPET,
+	FIX_DBGP_BASE,
 	FIX_HPET_BASE,
 	FIX_APIC_BASE,	/* local (CPU) APIC) -- required for SMP or not */
 	FIX_IO_APIC_BASE_0,



^ permalink raw reply related	[flat|nested] 29+ messages in thread

* Re: [linux-usb-devel] [RFC][PATCH 0/2] x86_64 Early usb debug port support.
       [not found]       ` <200612042001.09808.david-b@pacbell.net>
  2006-12-05 11:01         ` [linux-usb-devel] [RFC][PATCH 0/2] x86_64 Early usb debug port support Eric W. Biederman
@ 2006-12-05 11:18         ` Eric W. Biederman
  1 sibling, 0 replies; 29+ messages in thread
From: Eric W. Biederman @ 2006-12-05 11:18 UTC (permalink / raw)
  To: David Brownell
  Cc: linux-usb-devel, Peter Stuge, Stefan Reinauer, Greg KH,
	linux-kernel, Lu, Yinghai, Andi Kleen, linuxbios

David Brownell <david-b@pacbell.net> writes:

> On Sunday 03 December 2006 9:09 pm, Eric W. Biederman wrote:
>>
>> My driver should be sufficient to work with any EHCI in a realatively
>> clean state, and needs no special BIOS support just the hardware.
>> This appears to be different than the way the windows drivers are
>> using these debug devices.
>
> I'm glad to see someone finally got progress on this ... :)
>
> Separately, I forwarded some stuff I did last year ... maybe it'll help.
> You seem to have gotten further.  Have you also observed that the
> NetChip device seems to have polarity issues, such that only one
> end behaves properly?

I haven't yet.  But I don't think I have actually tried turning
the cable around in a very meaningful way yet either.  Possibly
this is something that has been fixed.  I know there are some
odd issues that I have encountered.  Like occasionally I would
need to stop the software on one side, or I would need to unplug
it when things got sufficiently confused.

> Note that this should **NOT** be specific to x86_64, since pretty
> much any PCI based EHCI can do this.  I wouldn't be able to use
> this on my NForce2 box, for example ...

So I took a quick look what it would take to do this truly generically
and even initializing this generally when console code typically
is registered looks like a problem.  Although only because we don't
get around to setting up pci_config space access helpers in a timely
manner.  To some extent that still sucks because you are still being
initialized before the general ehci-hcd code.

Regardless an arch specific i386 variant was easy to throw together.
It still needs a bit of work but it basically worked.

> As for EHCI registers, if this really _needs_ to live outside
> of drivers/usb/host, then I'd suggest <linux/usb/ehci.h> for
> the relevant declarations ... the <linux/usb/*.h> headers are
> provided exactly for sharing such declaration between otherwise
> unrelated parts of the tree.

Yep that sounds like the right thing to do.  I think I at least
need to be called from something outside of drivers/usb and may
need the code there.

Doing this in a truly generic fashion looks like a major pain.
Because all of the infrastructure needs to be fixed.

Eric

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [linux-usb-devel] [RFC][PATCH 0/2] x86_64 Early usb debug port support.
  2006-12-05 11:01         ` [linux-usb-devel] [RFC][PATCH 0/2] x86_64 Early usb debug port support Eric W. Biederman
@ 2006-12-06 17:31           ` Andi Kleen
  0 siblings, 0 replies; 29+ messages in thread
From: Andi Kleen @ 2006-12-06 17:31 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: David Brownell, linux-usb-devel, Peter Stuge, Stefan Reinauer,
	Greg KH, linux-kernel, Lu, Yinghai, linuxbios

On Tuesday 05 December 2006 12:01, Eric W. Biederman wrote:
> 
> Ok due to popular demands here is the slightly fixed patch that works
> on both i386 and x86_64.  For the i386 version you must not have
> HIGHMEM64G enabled. 
> 
> I just rolled it all into one patch as I'm to lazy to transmit all
> 3 of them.


You should definitely move the usb code to a separate file

Documentation/* needs to document the new option

Also for usb console keep should be made default because the output won't
be duplicated.


-Andi

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [LinuxBIOS] #57: libusb host program for PLX NET20DC debug device
  2006-12-03 12:52           ` Stefan Reinauer
@ 2006-12-03 13:11             ` Eric W. Biederman
  0 siblings, 0 replies; 29+ messages in thread
From: Eric W. Biederman @ 2006-12-03 13:11 UTC (permalink / raw)
  To: Stefan Reinauer; +Cc: Segher Boessenkool, Peter Stuge, linux-kernel, linuxbios

Stefan Reinauer <stepan@coresystems.de> writes:

> * Segher Boessenkool <segher@kernel.crashing.org> [061203 13:42]:
>> On LPC, yes -- or 0.5us or something like that.  On ISA it's
>> a lot faster, on PCI too -- better do 20 or so outb's to be
>> safe.
>
> The value's actually something we have been using as a rule of thumb
> while doing outb to port 80. Don't think these are routed to LPC, are
> they?

Depends on the destination address.  For 0x80 you can be fairly
certain it will be an unacknowledged cycle subtractively decoded
to the slowest bus on the system.  Or routed to 32 PCI or the LPC bus
if there is something to actually looking at the value so it is slow.

Since all I need is something that delays for about 50ms 50,000 outb
to port 0x80 looks like a good first approximation, and since it
only happens once it is probably better to just bump that count up
instead of trying to be precise about it and have an accurate timer.

I'm not at all convinced a usb console can be made sufficiently solid
to be useful.  But it is at least worth trying so we can clearly say
it doesn't work well.

Eric

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [LinuxBIOS] #57: libusb host program for PLX NET20DC debug device
  2006-12-03 12:42         ` Segher Boessenkool
@ 2006-12-03 12:52           ` Stefan Reinauer
  2006-12-03 13:11             ` Eric W. Biederman
  0 siblings, 1 reply; 29+ messages in thread
From: Stefan Reinauer @ 2006-12-03 12:52 UTC (permalink / raw)
  To: Segher Boessenkool
  Cc: Eric W. Biederman, Peter Stuge, linux-kernel, linuxbios

* Segher Boessenkool <segher@kernel.crashing.org> [061203 13:42]:
> On LPC, yes -- or 0.5us or something like that.  On ISA it's
> a lot faster, on PCI too -- better do 20 or so outb's to be
> safe.

The value's actually something we have been using as a rule of thumb
while doing outb to port 80. Don't think these are routed to LPC, are
they?

-- 
coresystems GmbH • Brahmsstr. 16 • D-79104 Freiburg i. Br.
      Tel.: +49 761 7668825 • Fax: +49 761 7664613
Email: info@coresystems.de  • http://www.coresystems.de/

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [LinuxBIOS] #57: libusb host program for PLX NET20DC debug device
  2006-12-03 12:01       ` Stefan Reinauer
@ 2006-12-03 12:42         ` Segher Boessenkool
  2006-12-03 12:52           ` Stefan Reinauer
  0 siblings, 1 reply; 29+ messages in thread
From: Segher Boessenkool @ 2006-12-03 12:42 UTC (permalink / raw)
  To: Stefan Reinauer; +Cc: Eric W. Biederman, Peter Stuge, linux-kernel, linuxbios

> you could use io delay, one outb uses roughly 1us iirc.

On LPC, yes -- or 0.5us or something like that.  On ISA it's
a lot faster, on PCI too -- better do 20 or so outb's to be
safe.  Or use a *real* timer instead, you'll have to abstract
this for portability anyway...


Segher


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [LinuxBIOS] #57: libusb host program for PLX NET20DC debug device
  2006-12-03 11:51     ` Eric W. Biederman
@ 2006-12-03 12:01       ` Stefan Reinauer
  2006-12-03 12:42         ` Segher Boessenkool
  0 siblings, 1 reply; 29+ messages in thread
From: Stefan Reinauer @ 2006-12-03 12:01 UTC (permalink / raw)
  To: Eric W. Biederman; +Cc: yhlu, Peter Stuge, linux-kernel, linuxbios

* Eric W. Biederman <ebiederm@xmission.com> [061203 12:51]:
> > BTW in kernel earlyprintk or prink, you could use
> > read_pci_config/write_pci_config before PCI system is loaded.
> 
> Yep thanks that seems to be working.  Now I just need
> to find an early delay and I can try this mess out!

you could use io delay, one outb uses roughly 1us iirc.

-- 
coresystems GmbH • Brahmsstr. 16 • D-79104 Freiburg i. Br.
      Tel.: +49 761 7668825 • Fax: +49 761 7664613
Email: info@coresystems.de  • http://www.coresystems.de/

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [LinuxBIOS] #57: libusb host program for PLX NET20DC debug device
  2006-12-02 20:47   ` yhlu
@ 2006-12-03 11:51     ` Eric W. Biederman
  2006-12-03 12:01       ` Stefan Reinauer
  0 siblings, 1 reply; 29+ messages in thread
From: Eric W. Biederman @ 2006-12-03 11:51 UTC (permalink / raw)
  To: yhlu; +Cc: Stefan Reinauer, Peter Stuge, linux-kernel, linuxbios

yhlu <yinghailu@gmail.com> writes:

> On 12/2/06, Eric W. Biederman <ebiederm@xmission.com> wrote:
>> Please yank the direct out of the filename if you are making something
>> like this out of it.  That was my note I was going direct to hardware
>> which is pretty much assumed if you are in LinuxBIOS.
>
> Yes, I adapted the code to used in LinuxBIOS, including CAR stage code
> and RAM satge code.
>
> I didn't have debug cable plugged yet.

Even if you did it wouldn't work right now.  My initial
version does initialize the ehci properly so it won't
find any usb devices.  I almost have that fixed,
but it looks like for the usb device reset I need
a usable delay function, so I can delay 50ms.  Grr...

> BTW in kernel earlyprintk or prink, you could use
> read_pci_config/write_pci_config before PCI system is loaded.

Yep thanks that seems to be working.  Now I just need
to find an early delay and I can try this mess out!

Eric


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [LinuxBIOS] #57: libusb host program for PLX NET20DC debug device
  2006-12-02 14:02 ` Eric W. Biederman
@ 2006-12-02 20:47   ` yhlu
  2006-12-03 11:51     ` Eric W. Biederman
  0 siblings, 1 reply; 29+ messages in thread
From: yhlu @ 2006-12-02 20:47 UTC (permalink / raw)
  To: Eric W. Biederman; +Cc: Stefan Reinauer, Peter Stuge, linux-kernel, linuxbios

On 12/2/06, Eric W. Biederman <ebiederm@xmission.com> wrote:
> Please yank the direct out of the filename if you are making something
> like this out of it.  That was my note I was going direct to hardware
> which is pretty much assumed if you are in LinuxBIOS.

Yes, I adapted the code to used in LinuxBIOS, including CAR stage code
and RAM satge code.

I didn't have debug cable plugged yet.

BTW in kernel earlyprintk or prink, you could use
read_pci_config/write_pci_config before PCI system is loaded.

YH

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [LinuxBIOS] #57: libusb host program for PLX NET20DC debug device
  2006-12-02  2:43 [LinuxBIOS] #57: libusb host program for PLX NET20DC debug device Lu, Yinghai
@ 2006-12-02 14:02 ` Eric W. Biederman
  2006-12-02 20:47   ` yhlu
  0 siblings, 1 reply; 29+ messages in thread
From: Eric W. Biederman @ 2006-12-02 14:02 UTC (permalink / raw)
  To: Lu, Yinghai; +Cc: Stefan Reinauer, Peter Stuge, linuxbios, linux-kernel

"Lu, Yinghai" <yinghai.lu@amd.com> writes:

> Thanks for the code.
>
> In LinuxBIOS,
> I put usbdevice_direct.c in lib/, and call it from usb2_init in
> mcp55_usb2.c
>
> Got 
> "No device in debug port"
>
> Waiting for cable, hope to get that cable next Tuesday.
>
> Will create usbdebug_direct_console.c in console/ for linuxbios_ram
> code.
> also usbdebug_direct_serial.c in pc80/ for cache_as_ram.c


Please yank the direct out of the filename if you are making something
like this out of it.  That was my note I was going direct to hardware
which is pretty much assumed if you are in LinuxBIOS.

Eric

^ permalink raw reply	[flat|nested] 29+ messages in thread

* RE: [LinuxBIOS] #57: libusb host program for PLX NET20DC debug device
@ 2006-12-02  2:43 Lu, Yinghai
  2006-12-02 14:02 ` Eric W. Biederman
  0 siblings, 1 reply; 29+ messages in thread
From: Lu, Yinghai @ 2006-12-02  2:43 UTC (permalink / raw)
  To: ebiederm, Greg KH
  Cc: Stefan Reinauer, Peter Stuge, linuxbios, linux-kernel, Andi Kleen

Thanks for the code.

In LinuxBIOS,
I put usbdevice_direct.c in lib/, and call it from usb2_init in
mcp55_usb2.c

Got 
"No device in debug port"

Waiting for cable, hope to get that cable next Tuesday.

Will create usbdebug_direct_console.c in console/ for linuxbios_ram
code.
also usbdebug_direct_serial.c in pc80/ for cache_as_ram.c


YH




^ permalink raw reply	[flat|nested] 29+ messages in thread

* RE: [LinuxBIOS] #57: libusb host program for PLX NET20DC debug device
@ 2006-12-01 22:10 Lu, Yinghai
  0 siblings, 0 replies; 29+ messages in thread
From: Lu, Yinghai @ 2006-12-01 22:10 UTC (permalink / raw)
  To: ebiederm, Greg KH, Andi Kleen; +Cc: Stefan Reinauer, linuxbios, linux-kernel

-----Original Message-----
From: ebiederm@xmission.com [mailto:ebiederm@xmission.com] 
Sent: Friday, December 01, 2006 1:15 PM

Peter Stuge <stuge-linuxbios@cdy.org> writes:

>> On Fri, Dec 01, 2006 at 11:19:16AM -0800, Greg KH wrote:
>>> Well, earlyprintk will not work, as you need PCI up and running.
>>
>> Not all of it though. LinuxBIOS will probably do just enough PCI
>> setup to talk to the EHCI controller and use the debug port _very_
>> soon after power on.

>Right.  For LinuxBIOS not a problem for earlyprintk in the kernel
>somethings might need to be refactored.  The challenge in the kernel
>is we don't know at build to how to do a pci_read_config...

early_pci_read_config?
Otherwise printk will come too late, and will not get output before pci
bus ops is set.

>The other hard part early in the kernel is the fact that the
>bar is memory mapped I/O.  Which means it will need to get mapped
>into the kernels page tables.

several entries to map 0xfc000000 ( PCI IO mem range) in page table in
head.S?

YH




^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [LinuxBIOS] #57: libusb host program for PLX NET20DC debug device
  2006-12-01 19:04   ` Peter Stuge
@ 2006-12-01 19:17     ` Greg KH
  0 siblings, 0 replies; 29+ messages in thread
From: Greg KH @ 2006-12-01 19:17 UTC (permalink / raw)
  To: Lu, Yinghai, Stefan Reinauer, Eric W. Biederman, linuxbios, linux-kernel

On Fri, Dec 01, 2006 at 08:04:26PM +0100, Peter Stuge wrote:
> On Fri, Dec 01, 2006 at 10:41:23AM -0800, Greg KH wrote:
> > On Fri, Dec 01, 2006 at 10:26:19AM -0800, Lu, Yinghai wrote:
> > > Anyone is working on creating one usb_serial_driver for USB debug
> > > device without using host debug port?
> > 
> > I can do that in about 15 minutes if you give me the device ids for
> > the usb debug device that you wish to have.
> 
> The host (aka remote) end of the NET20DC debug device has vid 0x0525
> and pid 0x127a.

You can use the usb-serial generic driver with those ids (as module
parameters) today, with no kernel changes needed.

> > Or you can also use the generic usb-serial driver today just fine
> > with no modification.  Have you had a problem with using that
> > option?
> 
> Does it check for a debug descriptor and attach to the device if one
> is found? Neat!

No, sorry, you need to use the device ids.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [LinuxBIOS] #57: libusb host program for PLX NET20DC debug device
  2006-12-01 18:41 ` Greg KH
@ 2006-12-01 19:04   ` Peter Stuge
  2006-12-01 19:17     ` Greg KH
  0 siblings, 1 reply; 29+ messages in thread
From: Peter Stuge @ 2006-12-01 19:04 UTC (permalink / raw)
  To: Greg KH
  Cc: Lu, Yinghai, Stefan Reinauer, Eric W. Biederman, linuxbios, linux-kernel

On Fri, Dec 01, 2006 at 10:41:23AM -0800, Greg KH wrote:
> On Fri, Dec 01, 2006 at 10:26:19AM -0800, Lu, Yinghai wrote:
> > Anyone is working on creating one usb_serial_driver for USB debug
> > device without using host debug port?
> 
> I can do that in about 15 minutes if you give me the device ids for
> the usb debug device that you wish to have.

The host (aka remote) end of the NET20DC debug device has vid 0x0525
and pid 0x127a.


> Or you can also use the generic usb-serial driver today just fine
> with no modification.  Have you had a problem with using that
> option?

Does it check for a debug descriptor and attach to the device if one
is found? Neat!


//Peter

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [LinuxBIOS] #57: libusb host program for PLX NET20DC debug device
  2006-12-01 18:26 Lu, Yinghai
@ 2006-12-01 18:41 ` Greg KH
  2006-12-01 19:04   ` Peter Stuge
  0 siblings, 1 reply; 29+ messages in thread
From: Greg KH @ 2006-12-01 18:41 UTC (permalink / raw)
  To: Lu, Yinghai
  Cc: Stefan Reinauer, Peter Stuge, Eric W. Biederman, linuxbios, linux-kernel

On Fri, Dec 01, 2006 at 10:26:19AM -0800, Lu, Yinghai wrote:
> -----Original Message-----
> From: Lu, Yinghai 
> 
> >To my understanding, you don't need to waiting for Eric's code.
> >You can use the cable on two systems without debug port support.
> >So just extend the program to make it can write the data too.
> 
> Greg,
> 
> Anyone is working on creating one usb_serial_driver for USB debug device
> without using host debug port?

I can do that in about 15 minutes if you give me the device ids for the
usb debug device that you wish to have.

Or you can also use the generic usb-serial driver today just fine with
no modification.  Have you had a problem with using that option?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 29+ messages in thread

* RE: [LinuxBIOS] #57: libusb host program for PLX NET20DC debug device
@ 2006-12-01 18:26 Lu, Yinghai
  2006-12-01 18:41 ` Greg KH
  0 siblings, 1 reply; 29+ messages in thread
From: Lu, Yinghai @ 2006-12-01 18:26 UTC (permalink / raw)
  To: Greg KH, Stefan Reinauer, Peter Stuge, Eric W. Biederman
  Cc: linuxbios, linux-kernel

-----Original Message-----
From: Lu, Yinghai 

>To my understanding, you don't need to waiting for Eric's code.
>You can use the cable on two systems without debug port support.
>So just extend the program to make it can write the data too.

Greg,

Anyone is working on creating one usb_serial_driver for USB debug device
without
using host debug port?

YH



^ permalink raw reply	[flat|nested] 29+ messages in thread

end of thread, other threads:[~2006-12-06 17:44 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2006-12-01 18:55 [LinuxBIOS] #57: libusb host program for PLX NET20DC debug device Lu, Yinghai
2006-12-01 19:19 ` Greg KH
2006-12-01 20:42   ` Peter Stuge
2006-12-01 21:15     ` Eric W. Biederman
2006-12-01 21:46       ` Peter Stuge
2006-12-01 23:02         ` Eric W. Biederman
2006-12-03 17:00           ` Peter Stuge
2006-12-03 23:03             ` Eric W. Biederman
2006-12-01 23:13   ` Eric W. Biederman
2006-12-03 15:49   ` Eric W. Biederman
2006-12-04  5:09     ` [RFC][PATCH 0/2] x86_64 Early usb debug port support Eric W. Biederman
2006-12-04  5:13       ` [RFC][PATCH 1/2] x86_64: Preallocate the fixmap pud and pmd entries Eric W. Biederman
2006-12-04  5:18         ` [RFC][PATCH 2/2] x86_64: earlyprintk usb debug device support Eric W. Biederman
     [not found]       ` <200612042001.09808.david-b@pacbell.net>
2006-12-05 11:01         ` [linux-usb-devel] [RFC][PATCH 0/2] x86_64 Early usb debug port support Eric W. Biederman
2006-12-06 17:31           ` Andi Kleen
2006-12-05 11:18         ` Eric W. Biederman
  -- strict thread matches above, loose matches on Subject: below --
2006-12-02  2:43 [LinuxBIOS] #57: libusb host program for PLX NET20DC debug device Lu, Yinghai
2006-12-02 14:02 ` Eric W. Biederman
2006-12-02 20:47   ` yhlu
2006-12-03 11:51     ` Eric W. Biederman
2006-12-03 12:01       ` Stefan Reinauer
2006-12-03 12:42         ` Segher Boessenkool
2006-12-03 12:52           ` Stefan Reinauer
2006-12-03 13:11             ` Eric W. Biederman
2006-12-01 22:10 Lu, Yinghai
2006-12-01 18:26 Lu, Yinghai
2006-12-01 18:41 ` Greg KH
2006-12-01 19:04   ` Peter Stuge
2006-12-01 19:17     ` Greg KH

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).