Merge usb changes for Gateworks Cambria boards:

o add support to byte swap EHCI descriptor contents; the IXP435
  has dual-EHCI controllers integral but descriptor contents are
  in big-endian format; this support is configured with the
  USB_EHCI_BIG_ENDIAN_DESC option and enabled with EHCI_SCFLG_BIGEDESC
o clean up EHCI USBMODE register setup during init; add #defines for
  bit values
o split debug support out into a new file and enable use through ddb
o while here remove a bunch of lingering netbsd-isms

Reviewed by:	imp
This commit is contained in:
Sam Leffler 2008-12-20 03:02:32 +00:00
commit bfa98d2bd1
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=186351
8 changed files with 506 additions and 374 deletions

View File

@ -1476,6 +1476,7 @@ dev/ubsec/ubsec.c optional ubsec
#
# USB support
dev/usb/ehci.c optional ehci
dev/usb/ehci_ddb.c optional ehci
dev/usb/ehci_pci.c optional ehci pci
dev/usb/hid.c optional usb
dev/usb/if_aue.c optional aue

View File

@ -627,6 +627,7 @@ BUS_DEBUG opt_bus.h
# options for USB support
USB_DEBUG opt_usb.h
USBVERBOSE opt_usb.h
USB_EHCI_BIG_ENDIAN_DESC opt_usb.h
U3G_DEBUG opt_u3g.h
UKBD_DFLT_KEYMAP opt_ukbd.h
UPLCOM_INTR_INTERVAL opt_uplcom.h

File diff suppressed because it is too large Load Diff

255
sys/dev/usb/ehci_ddb.c Normal file
View File

@ -0,0 +1,255 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "opt_ddb.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/endian.h>
#include <sys/bus.h>
#include <sys/lock.h>
#include <sys/lockmgr.h>
#include <machine/bus.h>
#include <machine/endian.h>
#include <dev/usb/usb.h>
#include <dev/usb/usbdi.h>
#include <dev/usb/usbdivar.h>
#include <dev/usb/ehcireg.h>
#include <dev/usb/ehcivar.h>
#ifdef DDB
#include <ddb/ddb.h>
#include <ddb/db_sym.h>
#else
#define db_printf printf
#endif
extern ehci_softc_t *theehci; /* XXX */
void
ehci_dump_regs(ehci_softc_t *sc)
{
int i;
db_printf("cmd=0x%08x, sts=0x%08x, ien=0x%08x\n",
EOREAD4(sc, EHCI_USBCMD),
EOREAD4(sc, EHCI_USBSTS),
EOREAD4(sc, EHCI_USBINTR));
db_printf("frindex=0x%08x ctrdsegm=0x%08x periodic=0x%08x async=0x%08x\n",
EOREAD4(sc, EHCI_FRINDEX),
EOREAD4(sc, EHCI_CTRLDSSEGMENT),
EOREAD4(sc, EHCI_PERIODICLISTBASE),
EOREAD4(sc, EHCI_ASYNCLISTADDR));
for (i = 1; i <= sc->sc_noport; i++)
db_printf("port %d status=0x%08x\n", i,
EOREAD4(sc, EHCI_PORTSC(i)));
}
static void
ehci_dump_link(ehci_softc_t *sc, ehci_link_t link, int type)
{
link = hc32toh(sc, link);
db_printf("0x%08x", link);
if (link & EHCI_LINK_TERMINATE)
db_printf("<T>");
else {
db_printf("<");
if (type) {
switch (EHCI_LINK_TYPE(link)) {
case EHCI_LINK_ITD: db_printf("ITD"); break;
case EHCI_LINK_QH: db_printf("QH"); break;
case EHCI_LINK_SITD: db_printf("SITD"); break;
case EHCI_LINK_FSTN: db_printf("FSTN"); break;
}
}
db_printf(">");
}
}
void
ehci_dump_sqtds(ehci_softc_t *sc, ehci_soft_qtd_t *sqtd)
{
int i;
u_int32_t stop;
stop = 0;
for (i = 0; sqtd && i < 20 && !stop; sqtd = sqtd->nextqtd, i++) {
ehci_dump_sqtd(sc, sqtd);
stop = sqtd->qtd.qtd_next & htohc32(sc, EHCI_LINK_TERMINATE);
}
if (sqtd)
db_printf("dump aborted, too many TDs\n");
}
void
ehci_dump_qtd(ehci_softc_t *sc, ehci_qtd_t *qtd)
{
u_int32_t s;
db_printf(" next="); ehci_dump_link(sc, qtd->qtd_next, 0);
db_printf(" altnext="); ehci_dump_link(sc, qtd->qtd_altnext, 0);
db_printf("\n");
s = hc32toh(sc, qtd->qtd_status);
db_printf(" status=0x%08x: toggle=%d bytes=0x%x ioc=%d c_page=0x%x\n",
s, EHCI_QTD_GET_TOGGLE(s), EHCI_QTD_GET_BYTES(s),
EHCI_QTD_GET_IOC(s), EHCI_QTD_GET_C_PAGE(s));
db_printf(" cerr=%d pid=%d stat=%b\n", EHCI_QTD_GET_CERR(s),
EHCI_QTD_GET_PID(s),
EHCI_QTD_GET_STATUS(s), EHCI_QTD_STATUS_BITS);
for (s = 0; s < 5; s++)
db_printf(" buffer[%d]=0x%08x\n", s, hc32toh(sc, qtd->qtd_buffer[s]));
}
void
ehci_dump_sqtd(ehci_softc_t *sc, ehci_soft_qtd_t *sqtd)
{
db_printf("QTD(%p) at 0x%08x:\n", sqtd, sqtd->physaddr);
ehci_dump_qtd(sc, &sqtd->qtd);
}
void
ehci_dump_sqh(ehci_softc_t *sc, ehci_soft_qh_t *sqh)
{
ehci_qh_t *qh = &sqh->qh;
u_int32_t endp, endphub;
db_printf("QH(%p) at 0x%08x:\n", sqh, sqh->physaddr);
db_printf(" sqtd=%p inactivesqtd=%p\n", sqh->sqtd, sqh->inactivesqtd);
db_printf(" link="); ehci_dump_link(sc, qh->qh_link, 1); db_printf("\n");
endp = hc32toh(sc, qh->qh_endp);
db_printf(" endp=0x%08x\n", endp);
db_printf(" addr=0x%02x inact=%d endpt=%d eps=%d dtc=%d hrecl=%d\n",
EHCI_QH_GET_ADDR(endp), EHCI_QH_GET_INACT(endp),
EHCI_QH_GET_ENDPT(endp), EHCI_QH_GET_EPS(endp),
EHCI_QH_GET_DTC(endp), EHCI_QH_GET_HRECL(endp));
db_printf(" mpl=0x%x ctl=%d nrl=%d\n",
EHCI_QH_GET_MPL(endp), EHCI_QH_GET_CTL(endp),
EHCI_QH_GET_NRL(endp));
endphub = hc32toh(sc, qh->qh_endphub);
db_printf(" endphub=0x%08x\n", endphub);
db_printf(" smask=0x%02x cmask=0x%02x huba=0x%02x port=%d mult=%d\n",
EHCI_QH_GET_SMASK(endphub), EHCI_QH_GET_CMASK(endphub),
EHCI_QH_GET_HUBA(endphub), EHCI_QH_GET_PORT(endphub),
EHCI_QH_GET_MULT(endphub));
db_printf(" curqtd="); ehci_dump_link(sc, qh->qh_curqtd, 0); db_printf("\n");
db_printf("Overlay qTD:\n");
ehci_dump_qtd(sc, &qh->qh_qtd);
}
void
ehci_dump_itd(ehci_softc_t *sc, struct ehci_soft_itd *itd)
{
ehci_isoc_trans_t t;
ehci_isoc_bufr_ptr_t b, b2, b3;
int i;
db_printf("ITD: next phys=%X\n", itd->itd.itd_next);
for (i = 0; i < 8;i++) {
t = hc32toh(sc, itd->itd.itd_ctl[i]);
db_printf("ITDctl %d: stat=%X len=%X ioc=%X pg=%X offs=%X\n", i,
EHCI_ITD_GET_STATUS(t), EHCI_ITD_GET_LEN(t),
EHCI_ITD_GET_IOC(t), EHCI_ITD_GET_PG(t),
EHCI_ITD_GET_OFFS(t));
}
db_printf("ITDbufr: ");
for (i = 0; i < 7; i++)
db_printf("%X,", EHCI_ITD_GET_BPTR(hc32toh(sc, itd->itd.itd_bufr[i])));
b = hc32toh(sc, itd->itd.itd_bufr[0]);
b2 = hc32toh(sc, itd->itd.itd_bufr[1]);
b3 = hc32toh(sc, itd->itd.itd_bufr[2]);
db_printf("\nep=%X daddr=%X dir=%d maxpkt=%X multi=%X\n",
EHCI_ITD_GET_EP(b), EHCI_ITD_GET_DADDR(b), EHCI_ITD_GET_DIR(b2),
EHCI_ITD_GET_MAXPKT(b2), EHCI_ITD_GET_MULTI(b3));
}
void
ehci_dump_sitd(ehci_softc_t *sc, struct ehci_soft_itd *itd)
{
db_printf("SITD %p next=%p prev=%p xfernext=%p physaddr=%X slot=%d\n",
itd, itd->u.frame_list.next, itd->u.frame_list.prev,
itd->xfer_next, itd->physaddr, itd->slot);
}
void
ehci_dump_exfer(struct ehci_xfer *ex)
{
#ifdef DIAGNOSTIC
db_printf("%p: sqtdstart %p end %p itdstart %p end %p isdone %d\n",
ex, ex->sqtdstart, ex->sqtdend, ex->itdstart,
ex->itdend, ex->isdone);
#else
db_printf("%p: sqtdstart %p end %p itdstart %p end %p\n",
ex, ex->sqtdstart, ex->sqtdend, ex->itdstart, ex->itdend);
#endif
}
#ifdef DDB
DB_SHOW_COMMAND(ehci, db_show_ehci)
{
if (!have_addr) {
db_printf("usage: show ehci <addr>\n");
return;
}
ehci_dump_regs((ehci_softc_t *) addr);
}
DB_SHOW_COMMAND(ehci_sqtds, db_show_ehci_sqtds)
{
if (!have_addr) {
db_printf("usage: show ehci_sqtds <addr>\n");
return;
}
ehci_dump_sqtds(theehci, (ehci_soft_qtd_t *) addr);
}
DB_SHOW_COMMAND(ehci_qtd, db_show_ehci_qtd)
{
if (!have_addr) {
db_printf("usage: show ehci_qtd <addr>\n");
return;
}
ehci_dump_qtd(theehci, (ehci_qtd_t *) addr);
}
DB_SHOW_COMMAND(ehci_sqh, db_show_ehci_sqh)
{
if (!have_addr) {
db_printf("usage: show ehci_sqh <addr>\n");
return;
}
ehci_dump_sqh(theehci, (ehci_soft_qh_t *) addr);
}
DB_SHOW_COMMAND(ehci_itd, db_show_ehci_itd)
{
if (!have_addr) {
db_printf("usage: show ehci_itd <addr>\n");
return;
}
ehci_dump_itd(theehci, (struct ehci_soft_itd *) addr);
}
DB_SHOW_COMMAND(ehci_sitd, db_show_ehci_sitd)
{
if (!have_addr) {
db_printf("usage: show ehci_sitd <addr>\n");
return;
}
ehci_dump_itd(theehci, (struct ehci_soft_itd *) addr);
}
DB_SHOW_COMMAND(ehci_xfer, db_show_ehci_xfer)
{
if (!have_addr) {
db_printf("usage: show ehci_xfer <addr>\n");
return;
}
ehci_dump_exfer((struct ehci_xfer *) addr);
}
#endif /* DDB */

View File

@ -61,8 +61,10 @@ __FBSDID("$FreeBSD$");
#include <sys/bus.h>
#include <sys/queue.h>
#include <sys/lockmgr.h>
#include <machine/bus.h>
#include <sys/rman.h>
#include <sys/endian.h>
#include <machine/bus.h>
#include <machine/resource.h>
#include <dev/pci/pcivar.h>

View File

@ -173,6 +173,15 @@
#define EHCI_PS_CS 0x00000001 /* RO connect status */
#define EHCI_PS_CLEAR (EHCI_PS_OCC|EHCI_PS_PEC|EHCI_PS_CSC)
#define EHCI_USBMODE 0x68 /* RW USB Device mode register */
#define EHCI_UM_CM 0x00000003 /* R/WO Controller Mode */
#define EHCI_UM_CM_IDLE 0x0 /* Idle */
#define EHCI_UM_CM_HOST 0x3 /* Host Controller */
#define EHCI_UM_ES 0x00000004 /* R/WO Endian Select */
#define EHCI_UM_ES_LE 0x0 /* Little-endian byte alignment */
#define EHCI_UM_ES_BE 0x4 /* Big-endian byte alignment */
#define EHCI_UM_SDIS 0x00000010 /* R/WO Stream Disable Mode */
#define EHCI_PORT_RESET_COMPLETE 2 /* ms */
#define EHCI_FLALIGN_ALIGN 0x1000
@ -279,6 +288,9 @@ typedef struct {
} ehci_qtd_t;
#define EHCI_QTD_ALIGN 32
#define EHCI_QTD_STATUS_BITS \
"\20\10ACTIVE\7HALTED\6BUFERR\5BABBLE\4XACTERR\3MISSED\2SPLIT\1PING"
/* Queue Head */
typedef struct {
ehci_link_t qh_link;

View File

@ -125,6 +125,7 @@ struct ehci_soft_islot {
#define EHCI_SCFLG_SETMODE 0x0004 /* set bridge mode again after init (Marvell) */
#define EHCI_SCFLG_FORCESPEED 0x0008 /* force speed (Marvell) */
#define EHCI_SCFLG_NORESTERM 0x0010 /* don't terminate reset sequence (Marvell) */
#define EHCI_SCFLG_BIGEDESC 0x0020 /* big-endian byte order descriptors */
typedef struct ehci_softc {
struct usbd_bus sc_bus; /* base device */
@ -132,22 +133,16 @@ typedef struct ehci_softc {
bus_space_tag_t iot;
bus_space_handle_t ioh;
bus_size_t sc_size;
#if defined(__FreeBSD__)
void *ih;
struct resource *io_res;
struct resource *irq_res;
#endif
u_int sc_offs; /* offset to operational regs */
char sc_vendor[32]; /* vendor string for root hub */
int sc_id_vendor; /* vendor ID for root hub */
u_int32_t sc_cmd; /* shadow of cmd reg during suspend */
#if defined(__NetBSD__) || defined(__OpenBSD__)
void *sc_powerhook; /* cookie from power hook */
void *sc_shutdownhook; /* cookie from shutdown hook */
#endif
u_int sc_ncomp;
u_int sc_npcomp;
@ -156,9 +151,6 @@ typedef struct ehci_softc {
usb_dma_t sc_fldma;
ehci_link_t *sc_flist;
u_int sc_flsize;
#ifndef __FreeBSD__
u_int sc_rand; /* XXX need proper intr scheduling */
#endif
struct ehci_soft_islot sc_islots[EHCI_INTRQHS];
@ -192,9 +184,6 @@ typedef struct ehci_softc {
struct callout sc_tmo_intrlist;
char sc_dying;
#if defined(__NetBSD__)
struct usb_dma_reserve sc_dma_reserve;
#endif
} ehci_softc_t;
#define EREAD1(sc, a) bus_space_read_1((sc)->iot, (sc)->ioh, (a))
@ -210,14 +199,77 @@ typedef struct ehci_softc {
#define EOWRITE2(sc, a, x) bus_space_write_2((sc)->iot, (sc)->ioh, (sc)->sc_offs+(a), (x))
#define EOWRITE4(sc, a, x) bus_space_write_4((sc)->iot, (sc)->ioh, (sc)->sc_offs+(a), (x))
#ifdef USB_EHCI_BIG_ENDIAN_DESC
/*
* Handle byte order conversion between host and ``host controller''.
* Typically the latter is little-endian but some controllers require
* big-endian in which case we may need to manually swap.
*/
static __inline uint32_t
htohc32(const struct ehci_softc *sc, const uint32_t v)
{
return sc->sc_flags & EHCI_SCFLG_BIGEDESC ? htobe32(v) : htole32(v);
}
static __inline uint16_t
htohc16(const struct ehci_softc *sc, const uint16_t v)
{
return sc->sc_flags & EHCI_SCFLG_BIGEDESC ? htobe16(v) : htole16(v);
}
static __inline uint32_t
hc32toh(const struct ehci_softc *sc, const uint32_t v)
{
return sc->sc_flags & EHCI_SCFLG_BIGEDESC ? be32toh(v) : le32toh(v);
}
static __inline uint16_t
hc16toh(const struct ehci_softc *sc, const uint16_t v)
{
return sc->sc_flags & EHCI_SCFLG_BIGEDESC ? be16toh(v) : le16toh(v);
}
#else
/*
* Normal little-endian only conversion routines.
*/
static __inline uint32_t
htohc32(const struct ehci_softc *sc, const uint32_t v)
{
return htole32(v);
}
static __inline uint16_t
htohc16(const struct ehci_softc *sc, const uint16_t v)
{
return htole16(v);
}
static __inline uint32_t
hc32toh(const struct ehci_softc *sc, const uint32_t v)
{
return le32toh(v);
}
static __inline uint16_t
hc16toh(const struct ehci_softc *sc, const uint16_t v)
{
return le16toh(v);
}
#endif
usbd_status ehci_init(ehci_softc_t *);
int ehci_intr(void *);
int ehci_detach(ehci_softc_t *, int);
#if defined(__NetBSD__) || defined(__OpenBSD__)
int ehci_activate(device_t, enum devact);
#endif
void ehci_power(int state, void *priv);
void ehci_shutdown(void *v);
#define MS_TO_TICKS(ms) ((ms) * hz / 1000)
void ehci_dump_regs(ehci_softc_t *);
void ehci_dump_sqtds(ehci_softc_t *, ehci_soft_qtd_t *);
void ehci_dump_qtd(ehci_softc_t *, ehci_qtd_t *);
void ehci_dump_sqtd(ehci_softc_t *, ehci_soft_qtd_t *);
void ehci_dump_sqh(ehci_softc_t *, ehci_soft_qh_t *);
void ehci_dump_itd(ehci_softc_t *, struct ehci_soft_itd *);
void ehci_dump_sitd(ehci_softc_t *, struct ehci_soft_itd *);
void ehci_dump_exfer(struct ehci_xfer *);

View File

@ -256,7 +256,8 @@ struct usb_attach_arg {
#define USBD_SHOW_DEVICE_CLASS 0x1
#define USBD_SHOW_INTERFACE_CLASS 0x2
int usbd_driver_load(module_t mod, int what, void *arg);
struct module;
int usbd_driver_load(struct module *mod, int what, void *arg);
static inline int
usb_get_port(device_t dev)