From: "Lu, Yinghai" <yinghai.lu@amd.com>
To: ebiederm@xmission.com, "Greg KH" <gregkh@suse.de>
Cc: "USB development list" <linux-usb-devel@lists.sourceforge.net>,
"Stefan Reinauer" <stepan@coresystems.de>,
"Peter Stuge" <stuge-linuxbios@cdy.org>,
linuxbios@linuxbios.org, linux-kernel@vger.kernel.org,
"Andi Kleen" <ak@suse.de>
Subject: RE: [RFC][PATCH 2/2] x86_64: earlyprintk usb debug device support.
Date: Mon, 4 Dec 2006 12:52:30 -0800 [thread overview]
Message-ID: <5986589C150B2F49A46483AC44C7BCA4907281@ssvlexmb2.amd.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 427 bytes --]
Eric,
Please check the version I modified for LinuxBIOS from your
usbdebug_direct.
Put the related info in
struct ehci_debug_info {
void *ehci_base;
void *ehci_op_base;
void *ehci_debug_base;
unsigned devnum;
unsigned endpoint_out;
unsigned endpoint_in;
int inited;
};
So for CAR stage code, I could put it the range after stack and easy to
retrieve.
YH
[-- Attachment #2: usbdebug_direct.h --]
[-- Type: application/octet-stream, Size: 608 bytes --]
#ifndef USBDEBUG_DIRECT_H
#define USBDEBUG_DIRECT_H
struct ehci_debug_info {
void *ehci_base;
void *ehci_op_base;
void *ehci_debug_base;
unsigned devnum;
unsigned endpoint_out;
unsigned endpoint_in;
int inited;
};
extern int usb_bulk_write_x(struct ehci_debug_info *dbg_info, const char *bytes, int size);
extern int usb_bulk_read_x(struct ehci_debug_info *dbg_info, void *data, int size);
extern int usbdebug_direct_init(unsigned ehci_bar, unsigned ehci_debug_offset, struct ehci_debug_info *dbg_info);
extern void set_ehci_base(unsigned ehci_base);
#endif
[-- Attachment #3: usbdebug_direct.c --]
[-- Type: application/octet-stream, Size: 14476 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.
*
*/
#ifndef __ROMCC__
#include <console/console.h>
#else
#if CONFIG_USE_PRINTK_IN_CAR==0
#define printk_debug(fmt, arg...) do {} while(0)
#endif
#endif
#include <arch/io.h>
#include <usbdebug_direct.h>
//#define EHCI_BAR 0xbfce0000
#define EHCI_BAR_BYTES 4096
//#define EHCI_DEBUG_OFFSET 0x98
/* 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 *ehci_debug_base)
{
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)
{
// with out_port 80? in CAR stage
// or tsc?
mdelay(10);
}
static int usb_wait_until_done(void *ehci_debug_base, unsigned ctrl)
{
unsigned pids, lpid;
int ret;
retry:
writel(ctrl | EHCI_CTRL_GO, ehci_debug_base + EHCI_CTRL);
ret = usb_wait_until_complete(ehci_debug_base);
pids = readl(ehci_debug_base + EHCI_PID);
lpid = (pids >> EHCI_PID_RECEIVED_SHIFT) & 0xff;
#if 1
if ((ret >= 0) && lpid != PID_ACK)
printk_debug("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(void *ehci_debug_base, 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 *ehci_debug_base, 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(void *ehci_debug_base, 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(ehci_debug_base, bytes, size);
writel(addr, ehci_debug_base + EHCI_ADDR);
writel(pids, ehci_debug_base + EHCI_PID);
ret = usb_wait_until_done(ehci_debug_base, ctrl);
if (ret < 0) {
printk_debug("out failed!: %d\n", ret);
return ret;
}
return ret;
}
int usb_bulk_write_x(struct ehci_debug_info *dbg_info, const char *bytes, int size)
{
return usb_bulk_write(dbg_info->ehci_debug_base, dbg_info->devnum, dbg_info->endpoint_out, bytes, size);
}
static int usb_bulk_read(void *ehci_debug_base, 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(ehci_debug_base, ctrl);
if (ret < 0) {
printk_debug("in failed!: %d\n", ret);
return ret;
}
if (size > ret)
size = ret;
usb_get_data(ehci_debug_base, data, size);
return ret;
}
int usb_bulk_read_x(struct ehci_debug_info *dbg_info, void *data, int size)
{
return usb_bulk_read(dbg_info->ehci_debug_base, dbg_info->devnum, dbg_info->endpoint_in, data, size);
}
static int usb_control_msg(void *ehci_debug_base, 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(ehci_debug_base, &req, sizeof(req));
writel(addr, ehci_debug_base + EHCI_ADDR);
writel(pids, ehci_debug_base + EHCI_PID);
ret = usb_wait_until_done(ehci_debug_base, ctrl);
if (ret < 0) {
//printk_debug("setup failed!: %d\n", ret);
return ret;
}
/* Read the result */
ret = usb_bulk_read(ehci_debug_base, address, 0, data, size);
#if 0
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(void *ehci_debug_base, int address, int requesttype, int request,
int value, int index)
{
return usb_control_msg(ehci_debug_base, address, requesttype, request, value, index, (void *)0, 0);
}
int usbdebug_direct_init(unsigned ehci_bar, unsigned ehci_debug_offset, struct ehci_debug_info *dbg_info)
{
void *ehci_base, *ehci_op_base, *ehci_debug_base;
struct usb_debug_descriptor debug;
unsigned endpoint_out, endpoint_in;
unsigned devnum;
unsigned hcsparams;
unsigned debug_port, n_ports;
unsigned val;
int result = -1;
int ret, i;
ehci_base = ehci_bar;
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;
printk_debug("debug_port: %d\n", debug_port);
printk_debug("n_ports: %d\n", n_ports);
for (i = 1; i <= n_ports; i++) {
val = readl(ehci_op_base + EHCI_PORTSC + (4*(i - 1)));
printk_debug("portsc%d: %08x\n", i, val);
}
#define EHCI_CTRL_CLAIM (EHCI_CTRL_OWNER | EHCI_CTRL_ENABLED | EHCI_CTRL_INUSE)
val = readl(ehci_debug_base + EHCI_CTRL);
printk_debug("ctrl: %04x\n", val);
writel(val | EHCI_CTRL_CLAIM, ehci_debug_base + EHCI_CTRL);
val = readl(ehci_debug_base + EHCI_CTRL);
printk_debug("ctrl: %04x\n", val);
if ((val & EHCI_CTRL_CLAIM) != EHCI_CTRL_CLAIM) {
printk_debug("No device in debug port\n");
writel(val & ~EHCI_CTRL_CLAIM, ehci_debug_base + EHCI_CTRL);
return -1;
}
printk_debug("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(ehci_debug_base, 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) {
printk_debug("Could not find attached debug device\n");
goto err;
}
if (ret < 0) {
printk_debug("Attach device is not a debug device\n");
goto err;
}
printk_debug("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(ehci_debug_base, devnum,
USB_TYPE_STANDARD | USB_RECIP_DEVICE,
USB_REQ_SET_ADDRESS, 127, 0);
printk_debug("set_address: %d\n", ret);
if (ret < 0) {
printk_debug("Could not move attached device to 127\n");
goto err;
}
devnum = 127;
}
/* Enable the debug interface */
ret = usb_control_msg0(ehci_debug_base, devnum, USB_TYPE_STANDARD | USB_RECIP_DEVICE,
USB_REQ_SET_FEATURE, USB_FT_DEBUG_MODE, 0);
printk_debug("set_feature_debug_mode: %d\n", ret);
if (ret < 0) {
printk_debug(" Could not enable the debug device\n");
goto err;
}
dbg_info->ehci_base = ehci_base;
dbg_info->ehci_op_base = ehci_op_base;
dbg_info->ehci_debug_base = ehci_debug_base;
dbg_info->devnum = devnum;
dbg_info->endpoint_out = endpoint_out;
dbg_info->endpoint_in = endpoint_in;
#if 0
{
//unsigned devnum = 2;
//unsigned endpoint_out = 1;
//unsigned endpoint_in = 0x82;
char *test_strings[] = {
"zero000\n",
"one1111\n",
"two2222\n",
"three33\n",
"four444\n",
"five555\n",
"six6666\n",
"seven77\n",
"eight88\n",
"nine999\n",
"tenaaaa\n",
"elevenb\n",
(void *)0,
};
char **ptr;
/* Perform a small write to get the even/odd data state in sync
*/
ret = usb_bulk_write(ehci_debug_base, devnum, endpoint_out, " ",1);
printk_debug("usb_bulk_write: %d\n", ret);
/* Write the test messages */
for (ptr = test_strings; *ptr; ptr++) {
/* Write a test message */
ret = usb_bulk_write(ehci_debug_base, devnum, endpoint_out,
*ptr, 8);
printk_debug("usb_bulk_write: %d\n", ret);
}
}
#endif
#if 0
/* Read some test messages */
for (;;) {
char buf[8];
ret = usb_bulk_read(ehci_debug_base, devnum, endpoint_in,
buf, sizeof(buf));
if (ret > 0)
printk_debug("%d:%*.*s", ret, ret, ret, buf);
}
#endif
#if 0
for (i = 0; i < 256; i+=1) {
val = readb(ehci_base + i);
printk_debug("%02x ", val);
if ((i & 0xf) == 0xf)
printk_debug("\n");
}
printk_debug("\n");
#endif
result = 0;
dbg_info->inited = 1;
return result;
err:
#ifdef EHCI_CTRL_CLAIM
val = readl(ehci_debug_base + EHCI_CTRL);
printk_debug("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);
printk_debug("ctrl: %08x\n", val);
#endif
return result;
}
next reply other threads:[~2006-12-04 20:59 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2006-12-04 20:52 Lu, Yinghai [this message]
-- strict thread matches above, loose matches on Subject: below --
2006-12-09 1:20 Lu, Yinghai
2006-12-07 3:20 Lu, Yinghai
2006-12-09 1:17 ` Greg KH
2006-12-05 3:18 Lu, Yinghai
2006-12-04 20:18 Lu, Yinghai
2006-12-04 20:33 ` Greg KH
2006-12-04 21:26 ` Eric W. Biederman
2006-12-05 0:45 ` Greg KH
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-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
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=5986589C150B2F49A46483AC44C7BCA4907281@ssvlexmb2.amd.com \
--to=yinghai.lu@amd.com \
--cc=ak@suse.de \
--cc=ebiederm@xmission.com \
--cc=gregkh@suse.de \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-usb-devel@lists.sourceforge.net \
--cc=linuxbios@linuxbios.org \
--cc=stepan@coresystems.de \
--cc=stuge-linuxbios@cdy.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®