mirror of
https://github.com/fbelavenuto/arpl.git
synced 2026-01-16 01:12:06 +08:00
first commit
This commit is contained in:
6
addons/ehci-pci/install-bromolow-3.10.108.sh
Normal file
6
addons/ehci-pci/install-bromolow-3.10.108.sh
Normal file
@@ -0,0 +1,6 @@
|
||||
if [ "${1}" = "rd" ]; then
|
||||
echo "Installing module(s) for ehci-pci"
|
||||
${INSMOD} "/modules/pci-quirks.ko"
|
||||
${INSMOD} "/modules/ehci-hcd.ko"
|
||||
${INSMOD} "/modules/ehci-pci.ko" ${PARAMS}
|
||||
fi
|
||||
5
addons/ehci-pci/install.sh
Normal file
5
addons/ehci-pci/install.sh
Normal file
@@ -0,0 +1,5 @@
|
||||
if [ "${1}" = "rd" ]; then
|
||||
echo "Installing modules for ehci-pci"
|
||||
${INSMOD} "/modules/ehci-hcd.ko"
|
||||
${INSMOD} "/modules/ehci-pci.ko" ${PARAMS}
|
||||
fi
|
||||
7
addons/ehci-pci/manifest.yml
Normal file
7
addons/ehci-pci/manifest.yml
Normal file
@@ -0,0 +1,7 @@
|
||||
version: 1
|
||||
name: ehci-pci
|
||||
description: "Driver for USB 2.0 Host Controller"
|
||||
available-for:
|
||||
broadwell-4.4.180:
|
||||
install-script: &script "install.sh"
|
||||
modules: true
|
||||
3
addons/ehci-pci/src/3.10.108/Makefile
Normal file
3
addons/ehci-pci/src/3.10.108/Makefile
Normal file
@@ -0,0 +1,3 @@
|
||||
obj-y += pci-quirks.o
|
||||
obj-m += ehci-hcd.o
|
||||
obj-m += ehci-pci.o
|
||||
980
addons/ehci-pci/src/3.10.108/ehci-dbg.c
Normal file
980
addons/ehci-pci/src/3.10.108/ehci-dbg.c
Normal file
@@ -0,0 +1,980 @@
|
||||
/*
|
||||
* Copyright (c) 2001-2002 by David Brownell
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/* this file is part of ehci-hcd.c */
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
/* check the values in the HCSPARAMS register
|
||||
* (host controller _Structural_ parameters)
|
||||
* see EHCI spec, Table 2-4 for each value
|
||||
*/
|
||||
static void dbg_hcs_params (struct ehci_hcd *ehci, char *label)
|
||||
{
|
||||
u32 params = ehci_readl(ehci, &ehci->caps->hcs_params);
|
||||
|
||||
ehci_dbg (ehci,
|
||||
"%s hcs_params 0x%x dbg=%d%s cc=%d pcc=%d%s%s ports=%d\n",
|
||||
label, params,
|
||||
HCS_DEBUG_PORT (params),
|
||||
HCS_INDICATOR (params) ? " ind" : "",
|
||||
HCS_N_CC (params),
|
||||
HCS_N_PCC (params),
|
||||
HCS_PORTROUTED (params) ? "" : " ordered",
|
||||
HCS_PPC (params) ? "" : " !ppc",
|
||||
HCS_N_PORTS (params)
|
||||
);
|
||||
/* Port routing, per EHCI 0.95 Spec, Section 2.2.5 */
|
||||
if (HCS_PORTROUTED (params)) {
|
||||
int i;
|
||||
char buf [46], tmp [7], byte;
|
||||
|
||||
buf[0] = 0;
|
||||
for (i = 0; i < HCS_N_PORTS (params); i++) {
|
||||
// FIXME MIPS won't readb() ...
|
||||
byte = readb (&ehci->caps->portroute[(i>>1)]);
|
||||
sprintf(tmp, "%d ",
|
||||
((i & 0x1) ? ((byte)&0xf) : ((byte>>4)&0xf)));
|
||||
strcat(buf, tmp);
|
||||
}
|
||||
ehci_dbg (ehci, "%s portroute %s\n",
|
||||
label, buf);
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
||||
static inline void dbg_hcs_params (struct ehci_hcd *ehci, char *label) {}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
/* check the values in the HCCPARAMS register
|
||||
* (host controller _Capability_ parameters)
|
||||
* see EHCI Spec, Table 2-5 for each value
|
||||
* */
|
||||
static void dbg_hcc_params (struct ehci_hcd *ehci, char *label)
|
||||
{
|
||||
u32 params = ehci_readl(ehci, &ehci->caps->hcc_params);
|
||||
|
||||
if (HCC_ISOC_CACHE (params)) {
|
||||
ehci_dbg (ehci,
|
||||
"%s hcc_params %04x caching frame %s%s%s\n",
|
||||
label, params,
|
||||
HCC_PGM_FRAMELISTLEN(params) ? "256/512/1024" : "1024",
|
||||
HCC_CANPARK(params) ? " park" : "",
|
||||
HCC_64BIT_ADDR(params) ? " 64 bit addr" : "");
|
||||
} else {
|
||||
ehci_dbg (ehci,
|
||||
"%s hcc_params %04x thresh %d uframes %s%s%s%s%s%s%s\n",
|
||||
label,
|
||||
params,
|
||||
HCC_ISOC_THRES(params),
|
||||
HCC_PGM_FRAMELISTLEN(params) ? "256/512/1024" : "1024",
|
||||
HCC_CANPARK(params) ? " park" : "",
|
||||
HCC_64BIT_ADDR(params) ? " 64 bit addr" : "",
|
||||
HCC_LPM(params) ? " LPM" : "",
|
||||
HCC_PER_PORT_CHANGE_EVENT(params) ? " ppce" : "",
|
||||
HCC_HW_PREFETCH(params) ? " hw prefetch" : "",
|
||||
HCC_32FRAME_PERIODIC_LIST(params) ?
|
||||
" 32 periodic list" : "");
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
||||
static inline void dbg_hcc_params (struct ehci_hcd *ehci, char *label) {}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
static void __maybe_unused
|
||||
dbg_qtd (const char *label, struct ehci_hcd *ehci, struct ehci_qtd *qtd)
|
||||
{
|
||||
ehci_dbg(ehci, "%s td %p n%08x %08x t%08x p0=%08x\n", label, qtd,
|
||||
hc32_to_cpup(ehci, &qtd->hw_next),
|
||||
hc32_to_cpup(ehci, &qtd->hw_alt_next),
|
||||
hc32_to_cpup(ehci, &qtd->hw_token),
|
||||
hc32_to_cpup(ehci, &qtd->hw_buf [0]));
|
||||
if (qtd->hw_buf [1])
|
||||
ehci_dbg(ehci, " p1=%08x p2=%08x p3=%08x p4=%08x\n",
|
||||
hc32_to_cpup(ehci, &qtd->hw_buf[1]),
|
||||
hc32_to_cpup(ehci, &qtd->hw_buf[2]),
|
||||
hc32_to_cpup(ehci, &qtd->hw_buf[3]),
|
||||
hc32_to_cpup(ehci, &qtd->hw_buf[4]));
|
||||
}
|
||||
|
||||
static void __maybe_unused
|
||||
dbg_qh (const char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
|
||||
{
|
||||
struct ehci_qh_hw *hw = qh->hw;
|
||||
|
||||
ehci_dbg (ehci, "%s qh %p n%08x info %x %x qtd %x\n", label,
|
||||
qh, hw->hw_next, hw->hw_info1, hw->hw_info2, hw->hw_current);
|
||||
dbg_qtd("overlay", ehci, (struct ehci_qtd *) &hw->hw_qtd_next);
|
||||
}
|
||||
|
||||
static void __maybe_unused
|
||||
dbg_itd (const char *label, struct ehci_hcd *ehci, struct ehci_itd *itd)
|
||||
{
|
||||
ehci_dbg (ehci, "%s [%d] itd %p, next %08x, urb %p\n",
|
||||
label, itd->frame, itd, hc32_to_cpu(ehci, itd->hw_next),
|
||||
itd->urb);
|
||||
ehci_dbg (ehci,
|
||||
" trans: %08x %08x %08x %08x %08x %08x %08x %08x\n",
|
||||
hc32_to_cpu(ehci, itd->hw_transaction[0]),
|
||||
hc32_to_cpu(ehci, itd->hw_transaction[1]),
|
||||
hc32_to_cpu(ehci, itd->hw_transaction[2]),
|
||||
hc32_to_cpu(ehci, itd->hw_transaction[3]),
|
||||
hc32_to_cpu(ehci, itd->hw_transaction[4]),
|
||||
hc32_to_cpu(ehci, itd->hw_transaction[5]),
|
||||
hc32_to_cpu(ehci, itd->hw_transaction[6]),
|
||||
hc32_to_cpu(ehci, itd->hw_transaction[7]));
|
||||
ehci_dbg (ehci,
|
||||
" buf: %08x %08x %08x %08x %08x %08x %08x\n",
|
||||
hc32_to_cpu(ehci, itd->hw_bufp[0]),
|
||||
hc32_to_cpu(ehci, itd->hw_bufp[1]),
|
||||
hc32_to_cpu(ehci, itd->hw_bufp[2]),
|
||||
hc32_to_cpu(ehci, itd->hw_bufp[3]),
|
||||
hc32_to_cpu(ehci, itd->hw_bufp[4]),
|
||||
hc32_to_cpu(ehci, itd->hw_bufp[5]),
|
||||
hc32_to_cpu(ehci, itd->hw_bufp[6]));
|
||||
ehci_dbg (ehci, " index: %d %d %d %d %d %d %d %d\n",
|
||||
itd->index[0], itd->index[1], itd->index[2],
|
||||
itd->index[3], itd->index[4], itd->index[5],
|
||||
itd->index[6], itd->index[7]);
|
||||
}
|
||||
|
||||
static void __maybe_unused
|
||||
dbg_sitd (const char *label, struct ehci_hcd *ehci, struct ehci_sitd *sitd)
|
||||
{
|
||||
ehci_dbg (ehci, "%s [%d] sitd %p, next %08x, urb %p\n",
|
||||
label, sitd->frame, sitd, hc32_to_cpu(ehci, sitd->hw_next),
|
||||
sitd->urb);
|
||||
ehci_dbg (ehci,
|
||||
" addr %08x sched %04x result %08x buf %08x %08x\n",
|
||||
hc32_to_cpu(ehci, sitd->hw_fullspeed_ep),
|
||||
hc32_to_cpu(ehci, sitd->hw_uframe),
|
||||
hc32_to_cpu(ehci, sitd->hw_results),
|
||||
hc32_to_cpu(ehci, sitd->hw_buf[0]),
|
||||
hc32_to_cpu(ehci, sitd->hw_buf[1]));
|
||||
}
|
||||
|
||||
static int __maybe_unused
|
||||
dbg_status_buf (char *buf, unsigned len, const char *label, u32 status)
|
||||
{
|
||||
return scnprintf (buf, len,
|
||||
"%s%sstatus %04x%s%s%s%s%s%s%s%s%s%s%s",
|
||||
label, label [0] ? " " : "", status,
|
||||
(status & STS_PPCE_MASK) ? " PPCE" : "",
|
||||
(status & STS_ASS) ? " Async" : "",
|
||||
(status & STS_PSS) ? " Periodic" : "",
|
||||
(status & STS_RECL) ? " Recl" : "",
|
||||
(status & STS_HALT) ? " Halt" : "",
|
||||
(status & STS_IAA) ? " IAA" : "",
|
||||
(status & STS_FATAL) ? " FATAL" : "",
|
||||
(status & STS_FLR) ? " FLR" : "",
|
||||
(status & STS_PCD) ? " PCD" : "",
|
||||
(status & STS_ERR) ? " ERR" : "",
|
||||
(status & STS_INT) ? " INT" : ""
|
||||
);
|
||||
}
|
||||
|
||||
static int __maybe_unused
|
||||
dbg_intr_buf (char *buf, unsigned len, const char *label, u32 enable)
|
||||
{
|
||||
return scnprintf (buf, len,
|
||||
"%s%sintrenable %02x%s%s%s%s%s%s%s",
|
||||
label, label [0] ? " " : "", enable,
|
||||
(enable & STS_PPCE_MASK) ? " PPCE" : "",
|
||||
(enable & STS_IAA) ? " IAA" : "",
|
||||
(enable & STS_FATAL) ? " FATAL" : "",
|
||||
(enable & STS_FLR) ? " FLR" : "",
|
||||
(enable & STS_PCD) ? " PCD" : "",
|
||||
(enable & STS_ERR) ? " ERR" : "",
|
||||
(enable & STS_INT) ? " INT" : ""
|
||||
);
|
||||
}
|
||||
|
||||
static const char *const fls_strings [] =
|
||||
{ "1024", "512", "256", "??" };
|
||||
|
||||
static int
|
||||
dbg_command_buf (char *buf, unsigned len, const char *label, u32 command)
|
||||
{
|
||||
return scnprintf (buf, len,
|
||||
"%s%scommand %07x %s%s%s%s%s%s=%d ithresh=%d%s%s%s%s "
|
||||
"period=%s%s %s",
|
||||
label, label [0] ? " " : "", command,
|
||||
(command & CMD_HIRD) ? " HIRD" : "",
|
||||
(command & CMD_PPCEE) ? " PPCEE" : "",
|
||||
(command & CMD_FSP) ? " FSP" : "",
|
||||
(command & CMD_ASPE) ? " ASPE" : "",
|
||||
(command & CMD_PSPE) ? " PSPE" : "",
|
||||
(command & CMD_PARK) ? " park" : "(park)",
|
||||
CMD_PARK_CNT (command),
|
||||
(command >> 16) & 0x3f,
|
||||
(command & CMD_LRESET) ? " LReset" : "",
|
||||
(command & CMD_IAAD) ? " IAAD" : "",
|
||||
(command & CMD_ASE) ? " Async" : "",
|
||||
(command & CMD_PSE) ? " Periodic" : "",
|
||||
fls_strings [(command >> 2) & 0x3],
|
||||
(command & CMD_RESET) ? " Reset" : "",
|
||||
(command & CMD_RUN) ? "RUN" : "HALT"
|
||||
);
|
||||
}
|
||||
|
||||
static int
|
||||
dbg_port_buf (char *buf, unsigned len, const char *label, int port, u32 status)
|
||||
{
|
||||
char *sig;
|
||||
|
||||
/* signaling state */
|
||||
switch (status & (3 << 10)) {
|
||||
case 0 << 10: sig = "se0"; break;
|
||||
case 1 << 10: sig = "k"; break; /* low speed */
|
||||
case 2 << 10: sig = "j"; break;
|
||||
default: sig = "?"; break;
|
||||
}
|
||||
|
||||
return scnprintf (buf, len,
|
||||
"%s%sport:%d status %06x %d %s%s%s%s%s%s "
|
||||
"sig=%s%s%s%s%s%s%s%s%s%s%s",
|
||||
label, label [0] ? " " : "", port, status,
|
||||
status>>25,/*device address */
|
||||
(status & PORT_SSTS)>>23 == PORTSC_SUSPEND_STS_ACK ?
|
||||
" ACK" : "",
|
||||
(status & PORT_SSTS)>>23 == PORTSC_SUSPEND_STS_NYET ?
|
||||
" NYET" : "",
|
||||
(status & PORT_SSTS)>>23 == PORTSC_SUSPEND_STS_STALL ?
|
||||
" STALL" : "",
|
||||
(status & PORT_SSTS)>>23 == PORTSC_SUSPEND_STS_ERR ?
|
||||
" ERR" : "",
|
||||
(status & PORT_POWER) ? " POWER" : "",
|
||||
(status & PORT_OWNER) ? " OWNER" : "",
|
||||
sig,
|
||||
(status & PORT_LPM) ? " LPM" : "",
|
||||
(status & PORT_RESET) ? " RESET" : "",
|
||||
(status & PORT_SUSPEND) ? " SUSPEND" : "",
|
||||
(status & PORT_RESUME) ? " RESUME" : "",
|
||||
(status & PORT_OCC) ? " OCC" : "",
|
||||
(status & PORT_OC) ? " OC" : "",
|
||||
(status & PORT_PEC) ? " PEC" : "",
|
||||
(status & PORT_PE) ? " PE" : "",
|
||||
(status & PORT_CSC) ? " CSC" : "",
|
||||
(status & PORT_CONNECT) ? " CONNECT" : "");
|
||||
}
|
||||
|
||||
#else
|
||||
static inline void __maybe_unused
|
||||
dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
|
||||
{}
|
||||
|
||||
static inline int __maybe_unused
|
||||
dbg_status_buf (char *buf, unsigned len, const char *label, u32 status)
|
||||
{ return 0; }
|
||||
|
||||
static inline int __maybe_unused
|
||||
dbg_command_buf (char *buf, unsigned len, const char *label, u32 command)
|
||||
{ return 0; }
|
||||
|
||||
static inline int __maybe_unused
|
||||
dbg_intr_buf (char *buf, unsigned len, const char *label, u32 enable)
|
||||
{ return 0; }
|
||||
|
||||
static inline int __maybe_unused
|
||||
dbg_port_buf (char *buf, unsigned len, const char *label, int port, u32 status)
|
||||
{ return 0; }
|
||||
|
||||
#endif /* DEBUG */
|
||||
|
||||
/* functions have the "wrong" filename when they're output... */
|
||||
#define dbg_status(ehci, label, status) { \
|
||||
char _buf [80]; \
|
||||
dbg_status_buf (_buf, sizeof _buf, label, status); \
|
||||
ehci_dbg (ehci, "%s\n", _buf); \
|
||||
}
|
||||
|
||||
#define dbg_cmd(ehci, label, command) { \
|
||||
char _buf [80]; \
|
||||
dbg_command_buf (_buf, sizeof _buf, label, command); \
|
||||
ehci_dbg (ehci, "%s\n", _buf); \
|
||||
}
|
||||
|
||||
#define dbg_port(ehci, label, port, status) { \
|
||||
char _buf [80]; \
|
||||
dbg_port_buf (_buf, sizeof _buf, label, port, status); \
|
||||
ehci_dbg (ehci, "%s\n", _buf); \
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
#ifdef STUB_DEBUG_FILES
|
||||
|
||||
static inline void create_debug_files (struct ehci_hcd *bus) { }
|
||||
static inline void remove_debug_files (struct ehci_hcd *bus) { }
|
||||
|
||||
#else
|
||||
|
||||
/* troubleshooting help: expose state in debugfs */
|
||||
|
||||
static int debug_async_open(struct inode *, struct file *);
|
||||
static int debug_periodic_open(struct inode *, struct file *);
|
||||
static int debug_registers_open(struct inode *, struct file *);
|
||||
static int debug_async_open(struct inode *, struct file *);
|
||||
|
||||
static ssize_t debug_output(struct file*, char __user*, size_t, loff_t*);
|
||||
static int debug_close(struct inode *, struct file *);
|
||||
|
||||
static const struct file_operations debug_async_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = debug_async_open,
|
||||
.read = debug_output,
|
||||
.release = debug_close,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
static const struct file_operations debug_periodic_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = debug_periodic_open,
|
||||
.read = debug_output,
|
||||
.release = debug_close,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
static const struct file_operations debug_registers_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = debug_registers_open,
|
||||
.read = debug_output,
|
||||
.release = debug_close,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static struct dentry *ehci_debug_root;
|
||||
|
||||
struct debug_buffer {
|
||||
ssize_t (*fill_func)(struct debug_buffer *); /* fill method */
|
||||
struct usb_bus *bus;
|
||||
struct mutex mutex; /* protect filling of buffer */
|
||||
size_t count; /* number of characters filled into buffer */
|
||||
char *output_buf;
|
||||
size_t alloc_size;
|
||||
};
|
||||
|
||||
#define speed_char(info1) ({ char tmp; \
|
||||
switch (info1 & (3 << 12)) { \
|
||||
case QH_FULL_SPEED: tmp = 'f'; break; \
|
||||
case QH_LOW_SPEED: tmp = 'l'; break; \
|
||||
case QH_HIGH_SPEED: tmp = 'h'; break; \
|
||||
default: tmp = '?'; break; \
|
||||
}; tmp; })
|
||||
|
||||
static inline char token_mark(struct ehci_hcd *ehci, __hc32 token)
|
||||
{
|
||||
__u32 v = hc32_to_cpu(ehci, token);
|
||||
|
||||
if (v & QTD_STS_ACTIVE)
|
||||
return '*';
|
||||
if (v & QTD_STS_HALT)
|
||||
return '-';
|
||||
if (!IS_SHORT_READ (v))
|
||||
return ' ';
|
||||
/* tries to advance through hw_alt_next */
|
||||
return '/';
|
||||
}
|
||||
|
||||
static void qh_lines (
|
||||
struct ehci_hcd *ehci,
|
||||
struct ehci_qh *qh,
|
||||
char **nextp,
|
||||
unsigned *sizep
|
||||
)
|
||||
{
|
||||
u32 scratch;
|
||||
u32 hw_curr;
|
||||
struct list_head *entry;
|
||||
struct ehci_qtd *td;
|
||||
unsigned temp;
|
||||
unsigned size = *sizep;
|
||||
char *next = *nextp;
|
||||
char mark;
|
||||
__le32 list_end = EHCI_LIST_END(ehci);
|
||||
struct ehci_qh_hw *hw = qh->hw;
|
||||
|
||||
if (hw->hw_qtd_next == list_end) /* NEC does this */
|
||||
mark = '@';
|
||||
else
|
||||
mark = token_mark(ehci, hw->hw_token);
|
||||
if (mark == '/') { /* qh_alt_next controls qh advance? */
|
||||
if ((hw->hw_alt_next & QTD_MASK(ehci))
|
||||
== ehci->async->hw->hw_alt_next)
|
||||
mark = '#'; /* blocked */
|
||||
else if (hw->hw_alt_next == list_end)
|
||||
mark = '.'; /* use hw_qtd_next */
|
||||
/* else alt_next points to some other qtd */
|
||||
}
|
||||
scratch = hc32_to_cpup(ehci, &hw->hw_info1);
|
||||
hw_curr = (mark == '*') ? hc32_to_cpup(ehci, &hw->hw_current) : 0;
|
||||
temp = scnprintf (next, size,
|
||||
"qh/%p dev%d %cs ep%d %08x %08x (%08x%c %s nak%d)",
|
||||
qh, scratch & 0x007f,
|
||||
speed_char (scratch),
|
||||
(scratch >> 8) & 0x000f,
|
||||
scratch, hc32_to_cpup(ehci, &hw->hw_info2),
|
||||
hc32_to_cpup(ehci, &hw->hw_token), mark,
|
||||
(cpu_to_hc32(ehci, QTD_TOGGLE) & hw->hw_token)
|
||||
? "data1" : "data0",
|
||||
(hc32_to_cpup(ehci, &hw->hw_alt_next) >> 1) & 0x0f);
|
||||
size -= temp;
|
||||
next += temp;
|
||||
|
||||
/* hc may be modifying the list as we read it ... */
|
||||
list_for_each (entry, &qh->qtd_list) {
|
||||
td = list_entry (entry, struct ehci_qtd, qtd_list);
|
||||
scratch = hc32_to_cpup(ehci, &td->hw_token);
|
||||
mark = ' ';
|
||||
if (hw_curr == td->qtd_dma)
|
||||
mark = '*';
|
||||
else if (hw->hw_qtd_next == cpu_to_hc32(ehci, td->qtd_dma))
|
||||
mark = '+';
|
||||
else if (QTD_LENGTH (scratch)) {
|
||||
if (td->hw_alt_next == ehci->async->hw->hw_alt_next)
|
||||
mark = '#';
|
||||
else if (td->hw_alt_next != list_end)
|
||||
mark = '/';
|
||||
}
|
||||
temp = snprintf (next, size,
|
||||
"\n\t%p%c%s len=%d %08x urb %p",
|
||||
td, mark, ({ char *tmp;
|
||||
switch ((scratch>>8)&0x03) {
|
||||
case 0: tmp = "out"; break;
|
||||
case 1: tmp = "in"; break;
|
||||
case 2: tmp = "setup"; break;
|
||||
default: tmp = "?"; break;
|
||||
} tmp;}),
|
||||
(scratch >> 16) & 0x7fff,
|
||||
scratch,
|
||||
td->urb);
|
||||
if (size < temp)
|
||||
temp = size;
|
||||
size -= temp;
|
||||
next += temp;
|
||||
if (temp == size)
|
||||
goto done;
|
||||
}
|
||||
|
||||
temp = snprintf (next, size, "\n");
|
||||
if (size < temp)
|
||||
temp = size;
|
||||
size -= temp;
|
||||
next += temp;
|
||||
|
||||
done:
|
||||
*sizep = size;
|
||||
*nextp = next;
|
||||
}
|
||||
|
||||
static ssize_t fill_async_buffer(struct debug_buffer *buf)
|
||||
{
|
||||
struct usb_hcd *hcd;
|
||||
struct ehci_hcd *ehci;
|
||||
unsigned long flags;
|
||||
unsigned temp, size;
|
||||
char *next;
|
||||
struct ehci_qh *qh;
|
||||
|
||||
hcd = bus_to_hcd(buf->bus);
|
||||
ehci = hcd_to_ehci (hcd);
|
||||
next = buf->output_buf;
|
||||
size = buf->alloc_size;
|
||||
|
||||
*next = 0;
|
||||
|
||||
/* dumps a snapshot of the async schedule.
|
||||
* usually empty except for long-term bulk reads, or head.
|
||||
* one QH per line, and TDs we know about
|
||||
*/
|
||||
spin_lock_irqsave (&ehci->lock, flags);
|
||||
for (qh = ehci->async->qh_next.qh; size > 0 && qh; qh = qh->qh_next.qh)
|
||||
qh_lines (ehci, qh, &next, &size);
|
||||
if (!list_empty(&ehci->async_unlink) && size > 0) {
|
||||
temp = scnprintf(next, size, "\nunlink =\n");
|
||||
size -= temp;
|
||||
next += temp;
|
||||
|
||||
list_for_each_entry(qh, &ehci->async_unlink, unlink_node) {
|
||||
if (size <= 0)
|
||||
break;
|
||||
qh_lines(ehci, qh, &next, &size);
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore (&ehci->lock, flags);
|
||||
|
||||
return strlen(buf->output_buf);
|
||||
}
|
||||
|
||||
#define DBG_SCHED_LIMIT 64
|
||||
static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
|
||||
{
|
||||
struct usb_hcd *hcd;
|
||||
struct ehci_hcd *ehci;
|
||||
unsigned long flags;
|
||||
union ehci_shadow p, *seen;
|
||||
unsigned temp, size, seen_count;
|
||||
char *next;
|
||||
unsigned i;
|
||||
__hc32 tag;
|
||||
|
||||
if (!(seen = kmalloc (DBG_SCHED_LIMIT * sizeof *seen, GFP_ATOMIC)))
|
||||
return 0;
|
||||
seen_count = 0;
|
||||
|
||||
hcd = bus_to_hcd(buf->bus);
|
||||
ehci = hcd_to_ehci (hcd);
|
||||
next = buf->output_buf;
|
||||
size = buf->alloc_size;
|
||||
|
||||
temp = scnprintf (next, size, "size = %d\n", ehci->periodic_size);
|
||||
size -= temp;
|
||||
next += temp;
|
||||
|
||||
/* dump a snapshot of the periodic schedule.
|
||||
* iso changes, interrupt usually doesn't.
|
||||
*/
|
||||
spin_lock_irqsave (&ehci->lock, flags);
|
||||
for (i = 0; i < ehci->periodic_size; i++) {
|
||||
p = ehci->pshadow [i];
|
||||
if (likely (!p.ptr))
|
||||
continue;
|
||||
tag = Q_NEXT_TYPE(ehci, ehci->periodic [i]);
|
||||
|
||||
temp = scnprintf (next, size, "%4d: ", i);
|
||||
size -= temp;
|
||||
next += temp;
|
||||
|
||||
do {
|
||||
struct ehci_qh_hw *hw;
|
||||
|
||||
switch (hc32_to_cpu(ehci, tag)) {
|
||||
case Q_TYPE_QH:
|
||||
hw = p.qh->hw;
|
||||
temp = scnprintf (next, size, " qh%d-%04x/%p",
|
||||
p.qh->period,
|
||||
hc32_to_cpup(ehci,
|
||||
&hw->hw_info2)
|
||||
/* uframe masks */
|
||||
& (QH_CMASK | QH_SMASK),
|
||||
p.qh);
|
||||
size -= temp;
|
||||
next += temp;
|
||||
/* don't repeat what follows this qh */
|
||||
for (temp = 0; temp < seen_count; temp++) {
|
||||
if (seen [temp].ptr != p.ptr)
|
||||
continue;
|
||||
if (p.qh->qh_next.ptr) {
|
||||
temp = scnprintf (next, size,
|
||||
" ...");
|
||||
size -= temp;
|
||||
next += temp;
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* show more info the first time around */
|
||||
if (temp == seen_count) {
|
||||
u32 scratch = hc32_to_cpup(ehci,
|
||||
&hw->hw_info1);
|
||||
struct ehci_qtd *qtd;
|
||||
char *type = "";
|
||||
|
||||
/* count tds, get ep direction */
|
||||
temp = 0;
|
||||
list_for_each_entry (qtd,
|
||||
&p.qh->qtd_list,
|
||||
qtd_list) {
|
||||
temp++;
|
||||
switch (0x03 & (hc32_to_cpu(
|
||||
ehci,
|
||||
qtd->hw_token) >> 8)) {
|
||||
case 0: type = "out"; continue;
|
||||
case 1: type = "in"; continue;
|
||||
}
|
||||
}
|
||||
|
||||
temp = scnprintf (next, size,
|
||||
" (%c%d ep%d%s "
|
||||
"[%d/%d] q%d p%d)",
|
||||
speed_char (scratch),
|
||||
scratch & 0x007f,
|
||||
(scratch >> 8) & 0x000f, type,
|
||||
p.qh->usecs, p.qh->c_usecs,
|
||||
temp,
|
||||
0x7ff & (scratch >> 16));
|
||||
|
||||
if (seen_count < DBG_SCHED_LIMIT)
|
||||
seen [seen_count++].qh = p.qh;
|
||||
} else
|
||||
temp = 0;
|
||||
tag = Q_NEXT_TYPE(ehci, hw->hw_next);
|
||||
p = p.qh->qh_next;
|
||||
break;
|
||||
case Q_TYPE_FSTN:
|
||||
temp = scnprintf (next, size,
|
||||
" fstn-%8x/%p", p.fstn->hw_prev,
|
||||
p.fstn);
|
||||
tag = Q_NEXT_TYPE(ehci, p.fstn->hw_next);
|
||||
p = p.fstn->fstn_next;
|
||||
break;
|
||||
case Q_TYPE_ITD:
|
||||
temp = scnprintf (next, size,
|
||||
" itd/%p", p.itd);
|
||||
tag = Q_NEXT_TYPE(ehci, p.itd->hw_next);
|
||||
p = p.itd->itd_next;
|
||||
break;
|
||||
case Q_TYPE_SITD:
|
||||
temp = scnprintf (next, size,
|
||||
" sitd%d-%04x/%p",
|
||||
p.sitd->stream->interval,
|
||||
hc32_to_cpup(ehci, &p.sitd->hw_uframe)
|
||||
& 0x0000ffff,
|
||||
p.sitd);
|
||||
tag = Q_NEXT_TYPE(ehci, p.sitd->hw_next);
|
||||
p = p.sitd->sitd_next;
|
||||
break;
|
||||
}
|
||||
size -= temp;
|
||||
next += temp;
|
||||
} while (p.ptr);
|
||||
|
||||
temp = scnprintf (next, size, "\n");
|
||||
size -= temp;
|
||||
next += temp;
|
||||
}
|
||||
spin_unlock_irqrestore (&ehci->lock, flags);
|
||||
kfree (seen);
|
||||
|
||||
return buf->alloc_size - size;
|
||||
}
|
||||
#undef DBG_SCHED_LIMIT
|
||||
|
||||
static const char *rh_state_string(struct ehci_hcd *ehci)
|
||||
{
|
||||
switch (ehci->rh_state) {
|
||||
case EHCI_RH_HALTED:
|
||||
return "halted";
|
||||
case EHCI_RH_SUSPENDED:
|
||||
return "suspended";
|
||||
case EHCI_RH_RUNNING:
|
||||
return "running";
|
||||
case EHCI_RH_STOPPING:
|
||||
return "stopping";
|
||||
}
|
||||
return "?";
|
||||
}
|
||||
|
||||
static ssize_t fill_registers_buffer(struct debug_buffer *buf)
|
||||
{
|
||||
struct usb_hcd *hcd;
|
||||
struct ehci_hcd *ehci;
|
||||
unsigned long flags;
|
||||
unsigned temp, size, i;
|
||||
char *next, scratch [80];
|
||||
static char fmt [] = "%*s\n";
|
||||
static char label [] = "";
|
||||
|
||||
hcd = bus_to_hcd(buf->bus);
|
||||
ehci = hcd_to_ehci (hcd);
|
||||
next = buf->output_buf;
|
||||
size = buf->alloc_size;
|
||||
|
||||
spin_lock_irqsave (&ehci->lock, flags);
|
||||
|
||||
if (!HCD_HW_ACCESSIBLE(hcd)) {
|
||||
size = scnprintf (next, size,
|
||||
"bus %s, device %s\n"
|
||||
"%s\n"
|
||||
"SUSPENDED (no register access)\n",
|
||||
hcd->self.controller->bus->name,
|
||||
dev_name(hcd->self.controller),
|
||||
hcd->product_desc);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Capability Registers */
|
||||
i = HC_VERSION(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
temp = scnprintf (next, size,
|
||||
"bus %s, device %s\n"
|
||||
"%s\n"
|
||||
"EHCI %x.%02x, rh state %s\n",
|
||||
hcd->self.controller->bus->name,
|
||||
dev_name(hcd->self.controller),
|
||||
hcd->product_desc,
|
||||
i >> 8, i & 0x0ff, rh_state_string(ehci));
|
||||
size -= temp;
|
||||
next += temp;
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
/* EHCI 0.96 and later may have "extended capabilities" */
|
||||
if (hcd->self.controller->bus == &pci_bus_type) {
|
||||
struct pci_dev *pdev;
|
||||
u32 offset, cap, cap2;
|
||||
unsigned count = 256/4;
|
||||
|
||||
pdev = to_pci_dev(ehci_to_hcd(ehci)->self.controller);
|
||||
offset = HCC_EXT_CAPS(ehci_readl(ehci,
|
||||
&ehci->caps->hcc_params));
|
||||
while (offset && count--) {
|
||||
pci_read_config_dword (pdev, offset, &cap);
|
||||
switch (cap & 0xff) {
|
||||
case 1:
|
||||
temp = scnprintf (next, size,
|
||||
"ownership %08x%s%s\n", cap,
|
||||
(cap & (1 << 24)) ? " linux" : "",
|
||||
(cap & (1 << 16)) ? " firmware" : "");
|
||||
size -= temp;
|
||||
next += temp;
|
||||
|
||||
offset += 4;
|
||||
pci_read_config_dword (pdev, offset, &cap2);
|
||||
temp = scnprintf (next, size,
|
||||
"SMI sts/enable 0x%08x\n", cap2);
|
||||
size -= temp;
|
||||
next += temp;
|
||||
break;
|
||||
case 0: /* illegal reserved capability */
|
||||
cap = 0;
|
||||
/* FALLTHROUGH */
|
||||
default: /* unknown */
|
||||
break;
|
||||
}
|
||||
temp = (cap >> 8) & 0xff;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// FIXME interpret both types of params
|
||||
i = ehci_readl(ehci, &ehci->caps->hcs_params);
|
||||
temp = scnprintf (next, size, "structural params 0x%08x\n", i);
|
||||
size -= temp;
|
||||
next += temp;
|
||||
|
||||
i = ehci_readl(ehci, &ehci->caps->hcc_params);
|
||||
temp = scnprintf (next, size, "capability params 0x%08x\n", i);
|
||||
size -= temp;
|
||||
next += temp;
|
||||
|
||||
/* Operational Registers */
|
||||
temp = dbg_status_buf (scratch, sizeof scratch, label,
|
||||
ehci_readl(ehci, &ehci->regs->status));
|
||||
temp = scnprintf (next, size, fmt, temp, scratch);
|
||||
size -= temp;
|
||||
next += temp;
|
||||
|
||||
temp = dbg_command_buf (scratch, sizeof scratch, label,
|
||||
ehci_readl(ehci, &ehci->regs->command));
|
||||
temp = scnprintf (next, size, fmt, temp, scratch);
|
||||
size -= temp;
|
||||
next += temp;
|
||||
|
||||
temp = dbg_intr_buf (scratch, sizeof scratch, label,
|
||||
ehci_readl(ehci, &ehci->regs->intr_enable));
|
||||
temp = scnprintf (next, size, fmt, temp, scratch);
|
||||
size -= temp;
|
||||
next += temp;
|
||||
|
||||
temp = scnprintf (next, size, "uframe %04x\n",
|
||||
ehci_read_frame_index(ehci));
|
||||
size -= temp;
|
||||
next += temp;
|
||||
|
||||
for (i = 1; i <= HCS_N_PORTS (ehci->hcs_params); i++) {
|
||||
temp = dbg_port_buf (scratch, sizeof scratch, label, i,
|
||||
ehci_readl(ehci,
|
||||
&ehci->regs->port_status[i - 1]));
|
||||
temp = scnprintf (next, size, fmt, temp, scratch);
|
||||
size -= temp;
|
||||
next += temp;
|
||||
if (i == HCS_DEBUG_PORT(ehci->hcs_params) && ehci->debug) {
|
||||
temp = scnprintf (next, size,
|
||||
" debug control %08x\n",
|
||||
ehci_readl(ehci,
|
||||
&ehci->debug->control));
|
||||
size -= temp;
|
||||
next += temp;
|
||||
}
|
||||
}
|
||||
|
||||
if (!list_empty(&ehci->async_unlink)) {
|
||||
temp = scnprintf(next, size, "async unlink qh %p\n",
|
||||
list_first_entry(&ehci->async_unlink,
|
||||
struct ehci_qh, unlink_node));
|
||||
size -= temp;
|
||||
next += temp;
|
||||
}
|
||||
|
||||
#ifdef EHCI_STATS
|
||||
temp = scnprintf (next, size,
|
||||
"irq normal %ld err %ld iaa %ld (lost %ld)\n",
|
||||
ehci->stats.normal, ehci->stats.error, ehci->stats.iaa,
|
||||
ehci->stats.lost_iaa);
|
||||
size -= temp;
|
||||
next += temp;
|
||||
|
||||
temp = scnprintf (next, size, "complete %ld unlink %ld\n",
|
||||
ehci->stats.complete, ehci->stats.unlink);
|
||||
size -= temp;
|
||||
next += temp;
|
||||
#endif
|
||||
|
||||
done:
|
||||
spin_unlock_irqrestore (&ehci->lock, flags);
|
||||
|
||||
return buf->alloc_size - size;
|
||||
}
|
||||
|
||||
static struct debug_buffer *alloc_buffer(struct usb_bus *bus,
|
||||
ssize_t (*fill_func)(struct debug_buffer *))
|
||||
{
|
||||
struct debug_buffer *buf;
|
||||
|
||||
buf = kzalloc(sizeof(struct debug_buffer), GFP_KERNEL);
|
||||
|
||||
if (buf) {
|
||||
buf->bus = bus;
|
||||
buf->fill_func = fill_func;
|
||||
mutex_init(&buf->mutex);
|
||||
buf->alloc_size = PAGE_SIZE;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int fill_buffer(struct debug_buffer *buf)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (!buf->output_buf)
|
||||
buf->output_buf = vmalloc(buf->alloc_size);
|
||||
|
||||
if (!buf->output_buf) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = buf->fill_func(buf);
|
||||
|
||||
if (ret >= 0) {
|
||||
buf->count = ret;
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t debug_output(struct file *file, char __user *user_buf,
|
||||
size_t len, loff_t *offset)
|
||||
{
|
||||
struct debug_buffer *buf = file->private_data;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&buf->mutex);
|
||||
if (buf->count == 0) {
|
||||
ret = fill_buffer(buf);
|
||||
if (ret != 0) {
|
||||
mutex_unlock(&buf->mutex);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&buf->mutex);
|
||||
|
||||
ret = simple_read_from_buffer(user_buf, len, offset,
|
||||
buf->output_buf, buf->count);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static int debug_close(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct debug_buffer *buf = file->private_data;
|
||||
|
||||
if (buf) {
|
||||
vfree(buf->output_buf);
|
||||
kfree(buf);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
static int debug_async_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
file->private_data = alloc_buffer(inode->i_private, fill_async_buffer);
|
||||
|
||||
return file->private_data ? 0 : -ENOMEM;
|
||||
}
|
||||
|
||||
static int debug_periodic_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct debug_buffer *buf;
|
||||
buf = alloc_buffer(inode->i_private, fill_periodic_buffer);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
buf->alloc_size = (sizeof(void *) == 4 ? 6 : 8)*PAGE_SIZE;
|
||||
file->private_data = buf;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int debug_registers_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
file->private_data = alloc_buffer(inode->i_private,
|
||||
fill_registers_buffer);
|
||||
|
||||
return file->private_data ? 0 : -ENOMEM;
|
||||
}
|
||||
|
||||
static inline void create_debug_files (struct ehci_hcd *ehci)
|
||||
{
|
||||
struct usb_bus *bus = &ehci_to_hcd(ehci)->self;
|
||||
|
||||
ehci->debug_dir = debugfs_create_dir(bus->bus_name, ehci_debug_root);
|
||||
if (!ehci->debug_dir)
|
||||
return;
|
||||
|
||||
if (!debugfs_create_file("async", S_IRUGO, ehci->debug_dir, bus,
|
||||
&debug_async_fops))
|
||||
goto file_error;
|
||||
|
||||
if (!debugfs_create_file("periodic", S_IRUGO, ehci->debug_dir, bus,
|
||||
&debug_periodic_fops))
|
||||
goto file_error;
|
||||
|
||||
if (!debugfs_create_file("registers", S_IRUGO, ehci->debug_dir, bus,
|
||||
&debug_registers_fops))
|
||||
goto file_error;
|
||||
|
||||
return;
|
||||
|
||||
file_error:
|
||||
debugfs_remove_recursive(ehci->debug_dir);
|
||||
}
|
||||
|
||||
static inline void remove_debug_files (struct ehci_hcd *ehci)
|
||||
{
|
||||
debugfs_remove_recursive(ehci->debug_dir);
|
||||
}
|
||||
|
||||
#endif /* STUB_DEBUG_FILES */
|
||||
1391
addons/ehci-pci/src/3.10.108/ehci-hcd.c
Normal file
1391
addons/ehci-pci/src/3.10.108/ehci-hcd.c
Normal file
File diff suppressed because it is too large
Load Diff
1139
addons/ehci-pci/src/3.10.108/ehci-hub.c
Normal file
1139
addons/ehci-pci/src/3.10.108/ehci-hub.c
Normal file
File diff suppressed because it is too large
Load Diff
245
addons/ehci-pci/src/3.10.108/ehci-mem.c
Normal file
245
addons/ehci-pci/src/3.10.108/ehci-mem.c
Normal file
@@ -0,0 +1,245 @@
|
||||
/*
|
||||
* Copyright (c) 2001 by David Brownell
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/* this file is part of ehci-hcd.c */
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* There's basically three types of memory:
|
||||
* - data used only by the HCD ... kmalloc is fine
|
||||
* - async and periodic schedules, shared by HC and HCD ... these
|
||||
* need to use dma_pool or dma_alloc_coherent
|
||||
* - driver buffers, read/written by HC ... single shot DMA mapped
|
||||
*
|
||||
* There's also "register" data (e.g. PCI or SOC), which is memory mapped.
|
||||
* No memory seen by this driver is pageable.
|
||||
*/
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* Allocate the key transfer structures from the previously allocated pool */
|
||||
|
||||
static inline void ehci_qtd_init(struct ehci_hcd *ehci, struct ehci_qtd *qtd,
|
||||
dma_addr_t dma)
|
||||
{
|
||||
memset (qtd, 0, sizeof *qtd);
|
||||
qtd->qtd_dma = dma;
|
||||
qtd->hw_token = cpu_to_hc32(ehci, QTD_STS_HALT);
|
||||
qtd->hw_next = EHCI_LIST_END(ehci);
|
||||
qtd->hw_alt_next = EHCI_LIST_END(ehci);
|
||||
INIT_LIST_HEAD (&qtd->qtd_list);
|
||||
}
|
||||
|
||||
static struct ehci_qtd *ehci_qtd_alloc (struct ehci_hcd *ehci, gfp_t flags)
|
||||
{
|
||||
struct ehci_qtd *qtd;
|
||||
dma_addr_t dma;
|
||||
|
||||
qtd = dma_pool_alloc (ehci->qtd_pool, flags, &dma);
|
||||
if (qtd != NULL) {
|
||||
ehci_qtd_init(ehci, qtd, dma);
|
||||
}
|
||||
return qtd;
|
||||
}
|
||||
|
||||
static inline void ehci_qtd_free (struct ehci_hcd *ehci, struct ehci_qtd *qtd)
|
||||
{
|
||||
dma_pool_free (ehci->qtd_pool, qtd, qtd->qtd_dma);
|
||||
}
|
||||
|
||||
|
||||
static void qh_destroy(struct ehci_hcd *ehci, struct ehci_qh *qh)
|
||||
{
|
||||
/* clean qtds first, and know this is not linked */
|
||||
if (!list_empty (&qh->qtd_list) || qh->qh_next.ptr) {
|
||||
ehci_dbg (ehci, "unused qh not empty!\n");
|
||||
BUG ();
|
||||
}
|
||||
if (qh->dummy)
|
||||
ehci_qtd_free (ehci, qh->dummy);
|
||||
dma_pool_free(ehci->qh_pool, qh->hw, qh->qh_dma);
|
||||
kfree(qh);
|
||||
}
|
||||
|
||||
static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, gfp_t flags)
|
||||
{
|
||||
struct ehci_qh *qh;
|
||||
dma_addr_t dma;
|
||||
|
||||
qh = kzalloc(sizeof *qh, GFP_ATOMIC);
|
||||
if (!qh)
|
||||
goto done;
|
||||
qh->hw = (struct ehci_qh_hw *)
|
||||
dma_pool_alloc(ehci->qh_pool, flags, &dma);
|
||||
if (!qh->hw)
|
||||
goto fail;
|
||||
memset(qh->hw, 0, sizeof *qh->hw);
|
||||
qh->qh_dma = dma;
|
||||
// INIT_LIST_HEAD (&qh->qh_list);
|
||||
INIT_LIST_HEAD (&qh->qtd_list);
|
||||
|
||||
/* dummy td enables safe urb queuing */
|
||||
qh->dummy = ehci_qtd_alloc (ehci, flags);
|
||||
if (qh->dummy == NULL) {
|
||||
ehci_dbg (ehci, "no dummy td\n");
|
||||
goto fail1;
|
||||
}
|
||||
done:
|
||||
return qh;
|
||||
fail1:
|
||||
dma_pool_free(ehci->qh_pool, qh->hw, qh->qh_dma);
|
||||
fail:
|
||||
kfree(qh);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* The queue heads and transfer descriptors are managed from pools tied
|
||||
* to each of the "per device" structures.
|
||||
* This is the initialisation and cleanup code.
|
||||
*/
|
||||
|
||||
static void ehci_mem_cleanup (struct ehci_hcd *ehci)
|
||||
{
|
||||
if (ehci->async)
|
||||
qh_destroy(ehci, ehci->async);
|
||||
ehci->async = NULL;
|
||||
|
||||
if (ehci->dummy)
|
||||
qh_destroy(ehci, ehci->dummy);
|
||||
ehci->dummy = NULL;
|
||||
|
||||
/* DMA consistent memory and pools */
|
||||
if (ehci->qtd_pool)
|
||||
dma_pool_destroy (ehci->qtd_pool);
|
||||
ehci->qtd_pool = NULL;
|
||||
|
||||
if (ehci->qh_pool) {
|
||||
dma_pool_destroy (ehci->qh_pool);
|
||||
ehci->qh_pool = NULL;
|
||||
}
|
||||
|
||||
if (ehci->itd_pool)
|
||||
dma_pool_destroy (ehci->itd_pool);
|
||||
ehci->itd_pool = NULL;
|
||||
|
||||
if (ehci->sitd_pool)
|
||||
dma_pool_destroy (ehci->sitd_pool);
|
||||
ehci->sitd_pool = NULL;
|
||||
|
||||
if (ehci->periodic)
|
||||
dma_free_coherent (ehci_to_hcd(ehci)->self.controller,
|
||||
ehci->periodic_size * sizeof (u32),
|
||||
ehci->periodic, ehci->periodic_dma);
|
||||
ehci->periodic = NULL;
|
||||
|
||||
/* shadow periodic table */
|
||||
kfree(ehci->pshadow);
|
||||
ehci->pshadow = NULL;
|
||||
}
|
||||
|
||||
/* remember to add cleanup code (above) if you add anything here */
|
||||
static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* QTDs for control/bulk/intr transfers */
|
||||
ehci->qtd_pool = dma_pool_create ("ehci_qtd",
|
||||
ehci_to_hcd(ehci)->self.controller,
|
||||
sizeof (struct ehci_qtd),
|
||||
32 /* byte alignment (for hw parts) */,
|
||||
4096 /* can't cross 4K */);
|
||||
if (!ehci->qtd_pool) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* QHs for control/bulk/intr transfers */
|
||||
ehci->qh_pool = dma_pool_create ("ehci_qh",
|
||||
ehci_to_hcd(ehci)->self.controller,
|
||||
sizeof(struct ehci_qh_hw),
|
||||
32 /* byte alignment (for hw parts) */,
|
||||
4096 /* can't cross 4K */);
|
||||
if (!ehci->qh_pool) {
|
||||
goto fail;
|
||||
}
|
||||
ehci->async = ehci_qh_alloc (ehci, flags);
|
||||
if (!ehci->async) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* ITD for high speed ISO transfers */
|
||||
ehci->itd_pool = dma_pool_create ("ehci_itd",
|
||||
ehci_to_hcd(ehci)->self.controller,
|
||||
sizeof (struct ehci_itd),
|
||||
32 /* byte alignment (for hw parts) */,
|
||||
4096 /* can't cross 4K */);
|
||||
if (!ehci->itd_pool) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* SITD for full/low speed split ISO transfers */
|
||||
ehci->sitd_pool = dma_pool_create ("ehci_sitd",
|
||||
ehci_to_hcd(ehci)->self.controller,
|
||||
sizeof (struct ehci_sitd),
|
||||
32 /* byte alignment (for hw parts) */,
|
||||
4096 /* can't cross 4K */);
|
||||
if (!ehci->sitd_pool) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Hardware periodic table */
|
||||
ehci->periodic = (__le32 *)
|
||||
dma_alloc_coherent (ehci_to_hcd(ehci)->self.controller,
|
||||
ehci->periodic_size * sizeof(__le32),
|
||||
&ehci->periodic_dma, 0);
|
||||
if (ehci->periodic == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (ehci->use_dummy_qh) {
|
||||
struct ehci_qh_hw *hw;
|
||||
ehci->dummy = ehci_qh_alloc(ehci, flags);
|
||||
if (!ehci->dummy)
|
||||
goto fail;
|
||||
|
||||
hw = ehci->dummy->hw;
|
||||
hw->hw_next = EHCI_LIST_END(ehci);
|
||||
hw->hw_qtd_next = EHCI_LIST_END(ehci);
|
||||
hw->hw_alt_next = EHCI_LIST_END(ehci);
|
||||
hw->hw_token &= ~QTD_STS_ACTIVE;
|
||||
ehci->dummy->hw = hw;
|
||||
|
||||
for (i = 0; i < ehci->periodic_size; i++)
|
||||
ehci->periodic[i] = ehci->dummy->qh_dma;
|
||||
} else {
|
||||
for (i = 0; i < ehci->periodic_size; i++)
|
||||
ehci->periodic[i] = EHCI_LIST_END(ehci);
|
||||
}
|
||||
|
||||
/* software shadow of hardware table */
|
||||
ehci->pshadow = kcalloc(ehci->periodic_size, sizeof(void *), flags);
|
||||
if (ehci->pshadow != NULL)
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
ehci_dbg (ehci, "couldn't init memory\n");
|
||||
ehci_mem_cleanup (ehci);
|
||||
return -ENOMEM;
|
||||
}
|
||||
464
addons/ehci-pci/src/3.10.108/ehci-pci.c
Normal file
464
addons/ehci-pci/src/3.10.108/ehci-pci.c
Normal file
@@ -0,0 +1,464 @@
|
||||
/*
|
||||
* EHCI HCD (Host Controller Driver) PCI Bus Glue.
|
||||
*
|
||||
* Copyright (c) 2000-2004 by David Brownell
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb/hcd.h>
|
||||
|
||||
#include "ehci.h"
|
||||
#include "pci-quirks.h"
|
||||
|
||||
#define DRIVER_DESC "EHCI PCI platform driver"
|
||||
|
||||
static const char hcd_name[] = "ehci-pci";
|
||||
|
||||
/* defined here to avoid adding to pci_ids.h for single instance use */
|
||||
#define PCI_DEVICE_ID_INTEL_CE4100_USB 0x2e70
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
#define PCI_DEVICE_ID_INTEL_QUARK_X1000_SOC 0x0939
|
||||
static inline bool is_intel_quark_x1000(struct pci_dev *pdev)
|
||||
{
|
||||
return pdev->vendor == PCI_VENDOR_ID_INTEL &&
|
||||
pdev->device == PCI_DEVICE_ID_INTEL_QUARK_X1000_SOC;
|
||||
}
|
||||
|
||||
/*
|
||||
* 0x84 is the offset of in/out threshold register,
|
||||
* and it is the same offset as the register of 'hostpc'.
|
||||
*/
|
||||
#define intel_quark_x1000_insnreg01 hostpc
|
||||
|
||||
/* Maximum usable threshold value is 0x7f dwords for both IN and OUT */
|
||||
#define INTEL_QUARK_X1000_EHCI_MAX_THRESHOLD 0x007f007f
|
||||
|
||||
/* called after powerup, by probe or system-pm "wakeup" */
|
||||
static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev)
|
||||
{
|
||||
int retval;
|
||||
|
||||
/* we expect static quirk code to handle the "extended capabilities"
|
||||
* (currently just BIOS handoff) allowed starting with EHCI 0.96
|
||||
*/
|
||||
|
||||
/* PCI Memory-Write-Invalidate cycle support is optional (uncommon) */
|
||||
retval = pci_set_mwi(pdev);
|
||||
if (!retval)
|
||||
ehci_dbg(ehci, "MWI active\n");
|
||||
|
||||
/* Reset the threshold limit */
|
||||
if (is_intel_quark_x1000(pdev)) {
|
||||
/*
|
||||
* For the Intel QUARK X1000, raise the I/O threshold to the
|
||||
* maximum usable value in order to improve performance.
|
||||
*/
|
||||
ehci_writel(ehci, INTEL_QUARK_X1000_EHCI_MAX_THRESHOLD,
|
||||
ehci->regs->intel_quark_x1000_insnreg01);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* called during probe() after chip reset completes */
|
||||
static int ehci_pci_setup(struct usb_hcd *hcd)
|
||||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
|
||||
struct pci_dev *p_smbus;
|
||||
u8 rev;
|
||||
u32 temp;
|
||||
int retval;
|
||||
|
||||
ehci->caps = hcd->regs;
|
||||
|
||||
/*
|
||||
* ehci_init() causes memory for DMA transfers to be
|
||||
* allocated. Thus, any vendor-specific workarounds based on
|
||||
* limiting the type of memory used for DMA transfers must
|
||||
* happen before ehci_setup() is called.
|
||||
*
|
||||
* Most other workarounds can be done either before or after
|
||||
* init and reset; they are located here too.
|
||||
*/
|
||||
switch (pdev->vendor) {
|
||||
case PCI_VENDOR_ID_TOSHIBA_2:
|
||||
/* celleb's companion chip */
|
||||
if (pdev->device == 0x01b5) {
|
||||
#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
|
||||
ehci->big_endian_mmio = 1;
|
||||
#else
|
||||
ehci_warn(ehci,
|
||||
"unsupported big endian Toshiba quirk\n");
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case PCI_VENDOR_ID_NVIDIA:
|
||||
/* NVidia reports that certain chips don't handle
|
||||
* QH, ITD, or SITD addresses above 2GB. (But TD,
|
||||
* data buffer, and periodic schedule are normal.)
|
||||
*/
|
||||
switch (pdev->device) {
|
||||
case 0x003c: /* MCP04 */
|
||||
case 0x005b: /* CK804 */
|
||||
case 0x00d8: /* CK8 */
|
||||
case 0x00e8: /* CK8S */
|
||||
if (pci_set_consistent_dma_mask(pdev,
|
||||
DMA_BIT_MASK(31)) < 0)
|
||||
ehci_warn(ehci, "can't enable NVidia "
|
||||
"workaround for >2GB RAM\n");
|
||||
break;
|
||||
|
||||
/* Some NForce2 chips have problems with selective suspend;
|
||||
* fixed in newer silicon.
|
||||
*/
|
||||
case 0x0068:
|
||||
if (pdev->revision < 0xa4)
|
||||
ehci->no_selective_suspend = 1;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case PCI_VENDOR_ID_INTEL:
|
||||
if (pdev->device == PCI_DEVICE_ID_INTEL_CE4100_USB)
|
||||
hcd->has_tt = 1;
|
||||
break;
|
||||
case PCI_VENDOR_ID_TDI:
|
||||
if (pdev->device == PCI_DEVICE_ID_TDI_EHCI)
|
||||
hcd->has_tt = 1;
|
||||
break;
|
||||
case PCI_VENDOR_ID_AMD:
|
||||
/* AMD PLL quirk */
|
||||
if (usb_amd_find_chipset_info())
|
||||
ehci->amd_pll_fix = 1;
|
||||
/* AMD8111 EHCI doesn't work, according to AMD errata */
|
||||
if (pdev->device == 0x7463) {
|
||||
ehci_info(ehci, "ignoring AMD8111 (errata)\n");
|
||||
retval = -EIO;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* EHCI controller on AMD SB700/SB800/Hudson-2/3 platforms may
|
||||
* read/write memory space which does not belong to it when
|
||||
* there is NULL pointer with T-bit set to 1 in the frame list
|
||||
* table. To avoid the issue, the frame list link pointer
|
||||
* should always contain a valid pointer to a inactive qh.
|
||||
*/
|
||||
if (pdev->device == 0x7808) {
|
||||
ehci->use_dummy_qh = 1;
|
||||
ehci_info(ehci, "applying AMD SB700/SB800/Hudson-2/3 EHCI dummy qh workaround\n");
|
||||
}
|
||||
break;
|
||||
case PCI_VENDOR_ID_VIA:
|
||||
if (pdev->device == 0x3104 && (pdev->revision & 0xf0) == 0x60) {
|
||||
u8 tmp;
|
||||
|
||||
/* The VT6212 defaults to a 1 usec EHCI sleep time which
|
||||
* hogs the PCI bus *badly*. Setting bit 5 of 0x4B makes
|
||||
* that sleep time use the conventional 10 usec.
|
||||
*/
|
||||
pci_read_config_byte(pdev, 0x4b, &tmp);
|
||||
if (tmp & 0x20)
|
||||
break;
|
||||
pci_write_config_byte(pdev, 0x4b, tmp | 0x20);
|
||||
}
|
||||
break;
|
||||
case PCI_VENDOR_ID_ATI:
|
||||
/* AMD PLL quirk */
|
||||
if (usb_amd_find_chipset_info())
|
||||
ehci->amd_pll_fix = 1;
|
||||
|
||||
/*
|
||||
* EHCI controller on AMD SB700/SB800/Hudson-2/3 platforms may
|
||||
* read/write memory space which does not belong to it when
|
||||
* there is NULL pointer with T-bit set to 1 in the frame list
|
||||
* table. To avoid the issue, the frame list link pointer
|
||||
* should always contain a valid pointer to a inactive qh.
|
||||
*/
|
||||
if (pdev->device == 0x4396) {
|
||||
ehci->use_dummy_qh = 1;
|
||||
ehci_info(ehci, "applying AMD SB700/SB800/Hudson-2/3 EHCI dummy qh workaround\n");
|
||||
}
|
||||
/* SB600 and old version of SB700 have a bug in EHCI controller,
|
||||
* which causes usb devices lose response in some cases.
|
||||
*/
|
||||
if ((pdev->device == 0x4386) || (pdev->device == 0x4396)) {
|
||||
p_smbus = pci_get_device(PCI_VENDOR_ID_ATI,
|
||||
PCI_DEVICE_ID_ATI_SBX00_SMBUS,
|
||||
NULL);
|
||||
if (!p_smbus)
|
||||
break;
|
||||
rev = p_smbus->revision;
|
||||
if ((pdev->device == 0x4386) || (rev == 0x3a)
|
||||
|| (rev == 0x3b)) {
|
||||
u8 tmp;
|
||||
ehci_info(ehci, "applying AMD SB600/SB700 USB "
|
||||
"freeze workaround\n");
|
||||
pci_read_config_byte(pdev, 0x53, &tmp);
|
||||
pci_write_config_byte(pdev, 0x53, tmp | (1<<3));
|
||||
}
|
||||
pci_dev_put(p_smbus);
|
||||
}
|
||||
break;
|
||||
case PCI_VENDOR_ID_NETMOS:
|
||||
/* MosChip frame-index-register bug */
|
||||
ehci_info(ehci, "applying MosChip frame-index workaround\n");
|
||||
ehci->frame_index_bug = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* optional debug port, normally in the first BAR */
|
||||
temp = pci_find_capability(pdev, PCI_CAP_ID_DBG);
|
||||
if (temp) {
|
||||
pci_read_config_dword(pdev, temp, &temp);
|
||||
temp >>= 16;
|
||||
if (((temp >> 13) & 7) == 1) {
|
||||
u32 hcs_params = ehci_readl(ehci,
|
||||
&ehci->caps->hcs_params);
|
||||
|
||||
temp &= 0x1fff;
|
||||
ehci->debug = hcd->regs + temp;
|
||||
temp = ehci_readl(ehci, &ehci->debug->control);
|
||||
ehci_info(ehci, "debug port %d%s\n",
|
||||
HCS_DEBUG_PORT(hcs_params),
|
||||
(temp & DBGP_ENABLED) ? " IN USE" : "");
|
||||
if (!(temp & DBGP_ENABLED))
|
||||
ehci->debug = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
retval = ehci_setup(hcd);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
/* These workarounds need to be applied after ehci_setup() */
|
||||
switch (pdev->vendor) {
|
||||
case PCI_VENDOR_ID_NEC:
|
||||
ehci->need_io_watchdog = 0;
|
||||
break;
|
||||
case PCI_VENDOR_ID_INTEL:
|
||||
ehci->need_io_watchdog = 0;
|
||||
break;
|
||||
case PCI_VENDOR_ID_NVIDIA:
|
||||
switch (pdev->device) {
|
||||
/* MCP89 chips on the MacBookAir3,1 give EPROTO when
|
||||
* fetching device descriptors unless LPM is disabled.
|
||||
* There are also intermittent problems enumerating
|
||||
* devices with PPCD enabled.
|
||||
*/
|
||||
case 0x0d9d:
|
||||
ehci_info(ehci, "disable ppcd for nvidia mcp89\n");
|
||||
ehci->has_ppcd = 0;
|
||||
ehci->command &= ~CMD_PPCEE;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* at least the Genesys GL880S needs fixup here */
|
||||
temp = HCS_N_CC(ehci->hcs_params) * HCS_N_PCC(ehci->hcs_params);
|
||||
temp &= 0x0f;
|
||||
if (temp && HCS_N_PORTS(ehci->hcs_params) > temp) {
|
||||
ehci_dbg(ehci, "bogus port configuration: "
|
||||
"cc=%d x pcc=%d < ports=%d\n",
|
||||
HCS_N_CC(ehci->hcs_params),
|
||||
HCS_N_PCC(ehci->hcs_params),
|
||||
HCS_N_PORTS(ehci->hcs_params));
|
||||
|
||||
switch (pdev->vendor) {
|
||||
case 0x17a0: /* GENESYS */
|
||||
/* GL880S: should be PORTS=2 */
|
||||
temp |= (ehci->hcs_params & ~0xf);
|
||||
ehci->hcs_params = temp;
|
||||
break;
|
||||
case PCI_VENDOR_ID_NVIDIA:
|
||||
/* NF4: should be PCC=10 */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Serial Bus Release Number is at PCI 0x60 offset */
|
||||
if (pdev->vendor == PCI_VENDOR_ID_STMICRO
|
||||
&& pdev->device == PCI_DEVICE_ID_STMICRO_USB_HOST)
|
||||
; /* ConneXT has no sbrn register */
|
||||
else
|
||||
pci_read_config_byte(pdev, 0x60, &ehci->sbrn);
|
||||
|
||||
/* Keep this around for a while just in case some EHCI
|
||||
* implementation uses legacy PCI PM support. This test
|
||||
* can be removed on 17 Dec 2009 if the dev_warn() hasn't
|
||||
* been triggered by then.
|
||||
*/
|
||||
if (!device_can_wakeup(&pdev->dev)) {
|
||||
u16 port_wake;
|
||||
|
||||
pci_read_config_word(pdev, 0x62, &port_wake);
|
||||
if (port_wake & 0x0001) {
|
||||
dev_warn(&pdev->dev, "Enabling legacy PCI PM\n");
|
||||
device_set_wakeup_capable(&pdev->dev, 1);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_RUNTIME
|
||||
if (ehci->no_selective_suspend && device_can_wakeup(&pdev->dev))
|
||||
ehci_warn(ehci, "selective suspend/wakeup unavailable\n");
|
||||
#endif
|
||||
|
||||
retval = ehci_pci_reinit(ehci, pdev);
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
/* suspend/resume, section 4.3 */
|
||||
|
||||
/* These routines rely on the PCI bus glue
|
||||
* to handle powerdown and wakeup, and currently also on
|
||||
* transceivers that don't need any software attention to set up
|
||||
* the right sort of wakeup.
|
||||
* Also they depend on separate root hub suspend/resume.
|
||||
*/
|
||||
|
||||
static bool usb_is_intel_switchable_ehci(struct pci_dev *pdev)
|
||||
{
|
||||
return pdev->class == PCI_CLASS_SERIAL_USB_EHCI &&
|
||||
pdev->vendor == PCI_VENDOR_ID_INTEL &&
|
||||
(pdev->device == 0x1E26 ||
|
||||
pdev->device == 0x8C2D ||
|
||||
pdev->device == 0x8C26 ||
|
||||
pdev->device == 0x9C26);
|
||||
}
|
||||
|
||||
static void ehci_enable_xhci_companion(void)
|
||||
{
|
||||
struct pci_dev *companion = NULL;
|
||||
|
||||
/* The xHCI and EHCI controllers are not on the same PCI slot */
|
||||
for_each_pci_dev(companion) {
|
||||
if (!usb_is_intel_switchable_xhci(companion))
|
||||
continue;
|
||||
usb_enable_xhci_ports(companion);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static int ehci_pci_resume(struct usb_hcd *hcd, bool hibernated)
|
||||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
|
||||
|
||||
/* The BIOS on systems with the Intel Panther Point chipset may or may
|
||||
* not support xHCI natively. That means that during system resume, it
|
||||
* may switch the ports back to EHCI so that users can use their
|
||||
* keyboard to select a kernel from GRUB after resume from hibernate.
|
||||
*
|
||||
* The BIOS is supposed to remember whether the OS had xHCI ports
|
||||
* enabled before resume, and switch the ports back to xHCI when the
|
||||
* BIOS/OS semaphore is written, but we all know we can't trust BIOS
|
||||
* writers.
|
||||
*
|
||||
* Unconditionally switch the ports back to xHCI after a system resume.
|
||||
* We can't tell whether the EHCI or xHCI controller will be resumed
|
||||
* first, so we have to do the port switchover in both drivers. Writing
|
||||
* a '1' to the port switchover registers should have no effect if the
|
||||
* port was already switched over.
|
||||
*/
|
||||
if (usb_is_intel_switchable_ehci(pdev))
|
||||
ehci_enable_xhci_companion();
|
||||
|
||||
if (ehci_resume(hcd, hibernated) != 0)
|
||||
(void) ehci_pci_reinit(ehci, pdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define ehci_suspend NULL
|
||||
#define ehci_pci_resume NULL
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static struct hc_driver __read_mostly ehci_pci_hc_driver;
|
||||
|
||||
static const struct ehci_driver_overrides pci_overrides __initconst = {
|
||||
.reset = ehci_pci_setup,
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* PCI driver selection metadata; PCI hotplugging uses this */
|
||||
static const struct pci_device_id pci_ids [] = { {
|
||||
/* handle any USB 2.0 EHCI controller */
|
||||
PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_EHCI, ~0),
|
||||
.driver_data = (unsigned long) &ehci_pci_hc_driver,
|
||||
}, {
|
||||
PCI_VDEVICE(STMICRO, PCI_DEVICE_ID_STMICRO_USB_HOST),
|
||||
.driver_data = (unsigned long) &ehci_pci_hc_driver,
|
||||
},
|
||||
{ /* end: all zeroes */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, pci_ids);
|
||||
|
||||
/* pci driver glue; this is a "new style" PCI driver module */
|
||||
static struct pci_driver ehci_pci_driver = {
|
||||
.name = (char *) hcd_name,
|
||||
.id_table = pci_ids,
|
||||
|
||||
.probe = usb_hcd_pci_probe,
|
||||
.remove = usb_hcd_pci_remove,
|
||||
.shutdown = usb_hcd_pci_shutdown,
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
.driver = {
|
||||
.pm = &usb_hcd_pci_pm_ops
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init ehci_pci_init(void)
|
||||
{
|
||||
if (usb_disabled())
|
||||
return -ENODEV;
|
||||
|
||||
pr_info("%s: " DRIVER_DESC "\n", hcd_name);
|
||||
|
||||
ehci_init_driver(&ehci_pci_hc_driver, &pci_overrides);
|
||||
|
||||
/* Entries for the PCI suspend/resume callbacks are special */
|
||||
ehci_pci_hc_driver.pci_suspend = ehci_suspend;
|
||||
ehci_pci_hc_driver.pci_resume = ehci_pci_resume;
|
||||
|
||||
return pci_register_driver(&ehci_pci_driver);
|
||||
}
|
||||
module_init(ehci_pci_init);
|
||||
|
||||
static void __exit ehci_pci_cleanup(void)
|
||||
{
|
||||
pci_unregister_driver(&ehci_pci_driver);
|
||||
}
|
||||
module_exit(ehci_pci_cleanup);
|
||||
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_AUTHOR("David Brownell");
|
||||
MODULE_AUTHOR("Alan Stern");
|
||||
MODULE_LICENSE("GPL");
|
||||
1368
addons/ehci-pci/src/3.10.108/ehci-q.c
Normal file
1368
addons/ehci-pci/src/3.10.108/ehci-q.c
Normal file
File diff suppressed because it is too large
Load Diff
2327
addons/ehci-pci/src/3.10.108/ehci-sched.c
Normal file
2327
addons/ehci-pci/src/3.10.108/ehci-sched.c
Normal file
File diff suppressed because it is too large
Load Diff
190
addons/ehci-pci/src/3.10.108/ehci-sysfs.c
Normal file
190
addons/ehci-pci/src/3.10.108/ehci-sysfs.c
Normal file
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* Copyright (C) 2007 by Alan Stern
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/* this file is part of ehci-hcd.c */
|
||||
|
||||
|
||||
/* Display the ports dedicated to the companion controller */
|
||||
static ssize_t show_companion(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct ehci_hcd *ehci;
|
||||
int nports, index, n;
|
||||
int count = PAGE_SIZE;
|
||||
char *ptr = buf;
|
||||
|
||||
ehci = hcd_to_ehci(dev_get_drvdata(dev));
|
||||
nports = HCS_N_PORTS(ehci->hcs_params);
|
||||
|
||||
for (index = 0; index < nports; ++index) {
|
||||
if (test_bit(index, &ehci->companion_ports)) {
|
||||
n = scnprintf(ptr, count, "%d\n", index + 1);
|
||||
ptr += n;
|
||||
count -= n;
|
||||
}
|
||||
}
|
||||
return ptr - buf;
|
||||
}
|
||||
|
||||
/*
|
||||
* Dedicate or undedicate a port to the companion controller.
|
||||
* Syntax is "[-]portnum", where a leading '-' sign means
|
||||
* return control of the port to the EHCI controller.
|
||||
*/
|
||||
static ssize_t store_companion(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct ehci_hcd *ehci;
|
||||
int portnum, new_owner;
|
||||
|
||||
ehci = hcd_to_ehci(dev_get_drvdata(dev));
|
||||
new_owner = PORT_OWNER; /* Owned by companion */
|
||||
if (sscanf(buf, "%d", &portnum) != 1)
|
||||
return -EINVAL;
|
||||
if (portnum < 0) {
|
||||
portnum = - portnum;
|
||||
new_owner = 0; /* Owned by EHCI */
|
||||
}
|
||||
if (portnum <= 0 || portnum > HCS_N_PORTS(ehci->hcs_params))
|
||||
return -ENOENT;
|
||||
portnum--;
|
||||
if (new_owner)
|
||||
set_bit(portnum, &ehci->companion_ports);
|
||||
else
|
||||
clear_bit(portnum, &ehci->companion_ports);
|
||||
set_owner(ehci, portnum, new_owner);
|
||||
return count;
|
||||
}
|
||||
static DEVICE_ATTR(companion, 0644, show_companion, store_companion);
|
||||
|
||||
|
||||
/*
|
||||
* Display / Set uframe_periodic_max
|
||||
*/
|
||||
static ssize_t show_uframe_periodic_max(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct ehci_hcd *ehci;
|
||||
int n;
|
||||
|
||||
ehci = hcd_to_ehci(dev_get_drvdata(dev));
|
||||
n = scnprintf(buf, PAGE_SIZE, "%d\n", ehci->uframe_periodic_max);
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
static ssize_t store_uframe_periodic_max(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct ehci_hcd *ehci;
|
||||
unsigned uframe_periodic_max;
|
||||
unsigned frame, uframe;
|
||||
unsigned short allocated_max;
|
||||
unsigned long flags;
|
||||
ssize_t ret;
|
||||
|
||||
ehci = hcd_to_ehci(dev_get_drvdata(dev));
|
||||
if (kstrtouint(buf, 0, &uframe_periodic_max) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (uframe_periodic_max < 100 || uframe_periodic_max >= 125) {
|
||||
ehci_info(ehci, "rejecting invalid request for "
|
||||
"uframe_periodic_max=%u\n", uframe_periodic_max);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = -EINVAL;
|
||||
|
||||
/*
|
||||
* lock, so that our checking does not race with possible periodic
|
||||
* bandwidth allocation through submitting new urbs.
|
||||
*/
|
||||
spin_lock_irqsave (&ehci->lock, flags);
|
||||
|
||||
/*
|
||||
* for request to decrease max periodic bandwidth, we have to check
|
||||
* every microframe in the schedule to see whether the decrease is
|
||||
* possible.
|
||||
*/
|
||||
if (uframe_periodic_max < ehci->uframe_periodic_max) {
|
||||
allocated_max = 0;
|
||||
|
||||
for (frame = 0; frame < ehci->periodic_size; ++frame)
|
||||
for (uframe = 0; uframe < 7; ++uframe)
|
||||
allocated_max = max(allocated_max,
|
||||
periodic_usecs (ehci, frame, uframe));
|
||||
|
||||
if (allocated_max > uframe_periodic_max) {
|
||||
ehci_info(ehci,
|
||||
"cannot decrease uframe_periodic_max becase "
|
||||
"periodic bandwidth is already allocated "
|
||||
"(%u > %u)\n",
|
||||
allocated_max, uframe_periodic_max);
|
||||
goto out_unlock;
|
||||
}
|
||||
}
|
||||
|
||||
/* increasing is always ok */
|
||||
|
||||
ehci_info(ehci, "setting max periodic bandwidth to %u%% "
|
||||
"(== %u usec/uframe)\n",
|
||||
100*uframe_periodic_max/125, uframe_periodic_max);
|
||||
|
||||
if (uframe_periodic_max != 100)
|
||||
ehci_warn(ehci, "max periodic bandwidth set is non-standard\n");
|
||||
|
||||
ehci->uframe_periodic_max = uframe_periodic_max;
|
||||
ret = count;
|
||||
|
||||
out_unlock:
|
||||
spin_unlock_irqrestore (&ehci->lock, flags);
|
||||
return ret;
|
||||
}
|
||||
static DEVICE_ATTR(uframe_periodic_max, 0644, show_uframe_periodic_max, store_uframe_periodic_max);
|
||||
|
||||
|
||||
static inline int create_sysfs_files(struct ehci_hcd *ehci)
|
||||
{
|
||||
struct device *controller = ehci_to_hcd(ehci)->self.controller;
|
||||
int i = 0;
|
||||
|
||||
/* with integrated TT there is no companion! */
|
||||
if (!ehci_is_TDI(ehci))
|
||||
i = device_create_file(controller, &dev_attr_companion);
|
||||
if (i)
|
||||
goto out;
|
||||
|
||||
i = device_create_file(controller, &dev_attr_uframe_periodic_max);
|
||||
out:
|
||||
return i;
|
||||
}
|
||||
|
||||
static inline void remove_sysfs_files(struct ehci_hcd *ehci)
|
||||
{
|
||||
struct device *controller = ehci_to_hcd(ehci)->self.controller;
|
||||
|
||||
/* with integrated TT there is no companion! */
|
||||
if (!ehci_is_TDI(ehci))
|
||||
device_remove_file(controller, &dev_attr_companion);
|
||||
|
||||
device_remove_file(controller, &dev_attr_uframe_periodic_max);
|
||||
}
|
||||
401
addons/ehci-pci/src/3.10.108/ehci-timer.c
Normal file
401
addons/ehci-pci/src/3.10.108/ehci-timer.c
Normal file
@@ -0,0 +1,401 @@
|
||||
/*
|
||||
* Copyright (C) 2012 by Alan Stern
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
/* This file is part of ehci-hcd.c */
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* Set a bit in the USBCMD register */
|
||||
static void ehci_set_command_bit(struct ehci_hcd *ehci, u32 bit)
|
||||
{
|
||||
ehci->command |= bit;
|
||||
ehci_writel(ehci, ehci->command, &ehci->regs->command);
|
||||
|
||||
/* unblock posted write */
|
||||
ehci_readl(ehci, &ehci->regs->command);
|
||||
}
|
||||
|
||||
/* Clear a bit in the USBCMD register */
|
||||
static void ehci_clear_command_bit(struct ehci_hcd *ehci, u32 bit)
|
||||
{
|
||||
ehci->command &= ~bit;
|
||||
ehci_writel(ehci, ehci->command, &ehci->regs->command);
|
||||
|
||||
/* unblock posted write */
|
||||
ehci_readl(ehci, &ehci->regs->command);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* EHCI timer support... Now using hrtimers.
|
||||
*
|
||||
* Lots of different events are triggered from ehci->hrtimer. Whenever
|
||||
* the timer routine runs, it checks each possible event; events that are
|
||||
* currently enabled and whose expiration time has passed get handled.
|
||||
* The set of enabled events is stored as a collection of bitflags in
|
||||
* ehci->enabled_hrtimer_events, and they are numbered in order of
|
||||
* increasing delay values (ranging between 1 ms and 100 ms).
|
||||
*
|
||||
* Rather than implementing a sorted list or tree of all pending events,
|
||||
* we keep track only of the lowest-numbered pending event, in
|
||||
* ehci->next_hrtimer_event. Whenever ehci->hrtimer gets restarted, its
|
||||
* expiration time is set to the timeout value for this event.
|
||||
*
|
||||
* As a result, events might not get handled right away; the actual delay
|
||||
* could be anywhere up to twice the requested delay. This doesn't
|
||||
* matter, because none of the events are especially time-critical. The
|
||||
* ones that matter most all have a delay of 1 ms, so they will be
|
||||
* handled after 2 ms at most, which is okay. In addition to this, we
|
||||
* allow for an expiration range of 1 ms.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Delay lengths for the hrtimer event types.
|
||||
* Keep this list sorted by delay length, in the same order as
|
||||
* the event types indexed by enum ehci_hrtimer_event in ehci.h.
|
||||
*/
|
||||
static unsigned event_delays_ns[] = {
|
||||
1 * NSEC_PER_MSEC, /* EHCI_HRTIMER_POLL_ASS */
|
||||
1 * NSEC_PER_MSEC, /* EHCI_HRTIMER_POLL_PSS */
|
||||
1 * NSEC_PER_MSEC, /* EHCI_HRTIMER_POLL_DEAD */
|
||||
1125 * NSEC_PER_USEC, /* EHCI_HRTIMER_UNLINK_INTR */
|
||||
2 * NSEC_PER_MSEC, /* EHCI_HRTIMER_FREE_ITDS */
|
||||
6 * NSEC_PER_MSEC, /* EHCI_HRTIMER_ASYNC_UNLINKS */
|
||||
10 * NSEC_PER_MSEC, /* EHCI_HRTIMER_IAA_WATCHDOG */
|
||||
10 * NSEC_PER_MSEC, /* EHCI_HRTIMER_DISABLE_PERIODIC */
|
||||
15 * NSEC_PER_MSEC, /* EHCI_HRTIMER_DISABLE_ASYNC */
|
||||
100 * NSEC_PER_MSEC, /* EHCI_HRTIMER_IO_WATCHDOG */
|
||||
};
|
||||
|
||||
/* Enable a pending hrtimer event */
|
||||
static void ehci_enable_event(struct ehci_hcd *ehci, unsigned event,
|
||||
bool resched)
|
||||
{
|
||||
ktime_t *timeout = &ehci->hr_timeouts[event];
|
||||
|
||||
if (resched)
|
||||
*timeout = ktime_add(ktime_get(),
|
||||
ktime_set(0, event_delays_ns[event]));
|
||||
ehci->enabled_hrtimer_events |= (1 << event);
|
||||
|
||||
/* Track only the lowest-numbered pending event */
|
||||
if (event < ehci->next_hrtimer_event) {
|
||||
ehci->next_hrtimer_event = event;
|
||||
hrtimer_start_range_ns(&ehci->hrtimer, *timeout,
|
||||
NSEC_PER_MSEC, HRTIMER_MODE_ABS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Poll the STS_ASS status bit; see when it agrees with CMD_ASE */
|
||||
static void ehci_poll_ASS(struct ehci_hcd *ehci)
|
||||
{
|
||||
unsigned actual, want;
|
||||
|
||||
/* Don't enable anything if the controller isn't running (e.g., died) */
|
||||
if (ehci->rh_state != EHCI_RH_RUNNING)
|
||||
return;
|
||||
|
||||
want = (ehci->command & CMD_ASE) ? STS_ASS : 0;
|
||||
actual = ehci_readl(ehci, &ehci->regs->status) & STS_ASS;
|
||||
|
||||
if (want != actual) {
|
||||
|
||||
/* Poll again later, but give up after about 2-4 ms */
|
||||
if (ehci->ASS_poll_count++ < 2) {
|
||||
ehci_enable_event(ehci, EHCI_HRTIMER_POLL_ASS, true);
|
||||
return;
|
||||
}
|
||||
ehci_dbg(ehci, "Waited too long for the async schedule status (%x/%x), giving up\n",
|
||||
want, actual);
|
||||
}
|
||||
ehci->ASS_poll_count = 0;
|
||||
|
||||
/* The status is up-to-date; restart or stop the schedule as needed */
|
||||
if (want == 0) { /* Stopped */
|
||||
if (ehci->async_count > 0)
|
||||
ehci_set_command_bit(ehci, CMD_ASE);
|
||||
|
||||
} else { /* Running */
|
||||
if (ehci->async_count == 0) {
|
||||
|
||||
/* Turn off the schedule after a while */
|
||||
ehci_enable_event(ehci, EHCI_HRTIMER_DISABLE_ASYNC,
|
||||
true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Turn off the async schedule after a brief delay */
|
||||
static void ehci_disable_ASE(struct ehci_hcd *ehci)
|
||||
{
|
||||
ehci_clear_command_bit(ehci, CMD_ASE);
|
||||
}
|
||||
|
||||
|
||||
/* Poll the STS_PSS status bit; see when it agrees with CMD_PSE */
|
||||
static void ehci_poll_PSS(struct ehci_hcd *ehci)
|
||||
{
|
||||
unsigned actual, want;
|
||||
|
||||
/* Don't do anything if the controller isn't running (e.g., died) */
|
||||
if (ehci->rh_state != EHCI_RH_RUNNING)
|
||||
return;
|
||||
|
||||
want = (ehci->command & CMD_PSE) ? STS_PSS : 0;
|
||||
actual = ehci_readl(ehci, &ehci->regs->status) & STS_PSS;
|
||||
|
||||
if (want != actual) {
|
||||
|
||||
/* Poll again later, but give up after about 2-4 ms */
|
||||
if (ehci->PSS_poll_count++ < 2) {
|
||||
ehci_enable_event(ehci, EHCI_HRTIMER_POLL_PSS, true);
|
||||
return;
|
||||
}
|
||||
ehci_dbg(ehci, "Waited too long for the periodic schedule status (%x/%x), giving up\n",
|
||||
want, actual);
|
||||
}
|
||||
ehci->PSS_poll_count = 0;
|
||||
|
||||
/* The status is up-to-date; restart or stop the schedule as needed */
|
||||
if (want == 0) { /* Stopped */
|
||||
if (ehci->periodic_count > 0)
|
||||
ehci_set_command_bit(ehci, CMD_PSE);
|
||||
|
||||
} else { /* Running */
|
||||
if (ehci->periodic_count == 0) {
|
||||
|
||||
/* Turn off the schedule after a while */
|
||||
ehci_enable_event(ehci, EHCI_HRTIMER_DISABLE_PERIODIC,
|
||||
true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Turn off the periodic schedule after a brief delay */
|
||||
static void ehci_disable_PSE(struct ehci_hcd *ehci)
|
||||
{
|
||||
ehci_clear_command_bit(ehci, CMD_PSE);
|
||||
}
|
||||
|
||||
|
||||
/* Poll the STS_HALT status bit; see when a dead controller stops */
|
||||
static void ehci_handle_controller_death(struct ehci_hcd *ehci)
|
||||
{
|
||||
if (!(ehci_readl(ehci, &ehci->regs->status) & STS_HALT)) {
|
||||
|
||||
/* Give up after a few milliseconds */
|
||||
if (ehci->died_poll_count++ < 5) {
|
||||
/* Try again later */
|
||||
ehci_enable_event(ehci, EHCI_HRTIMER_POLL_DEAD, true);
|
||||
return;
|
||||
}
|
||||
ehci_warn(ehci, "Waited too long for the controller to stop, giving up\n");
|
||||
}
|
||||
|
||||
/* Clean up the mess */
|
||||
ehci->rh_state = EHCI_RH_HALTED;
|
||||
ehci_writel(ehci, 0, &ehci->regs->configured_flag);
|
||||
ehci_writel(ehci, 0, &ehci->regs->intr_enable);
|
||||
ehci_work(ehci);
|
||||
end_unlink_async(ehci);
|
||||
|
||||
/* Not in process context, so don't try to reset the controller */
|
||||
}
|
||||
|
||||
|
||||
/* Handle unlinked interrupt QHs once they are gone from the hardware */
|
||||
static void ehci_handle_intr_unlinks(struct ehci_hcd *ehci)
|
||||
{
|
||||
bool stopped = (ehci->rh_state < EHCI_RH_RUNNING);
|
||||
|
||||
/*
|
||||
* Process all the QHs on the intr_unlink list that were added
|
||||
* before the current unlink cycle began. The list is in
|
||||
* temporal order, so stop when we reach the first entry in the
|
||||
* current cycle. But if the root hub isn't running then
|
||||
* process all the QHs on the list.
|
||||
*/
|
||||
ehci->intr_unlinking = true;
|
||||
while (!list_empty(&ehci->intr_unlink)) {
|
||||
struct ehci_qh *qh;
|
||||
|
||||
qh = list_first_entry(&ehci->intr_unlink, struct ehci_qh,
|
||||
unlink_node);
|
||||
if (!stopped && qh->unlink_cycle == ehci->intr_unlink_cycle)
|
||||
break;
|
||||
list_del(&qh->unlink_node);
|
||||
end_unlink_intr(ehci, qh);
|
||||
}
|
||||
|
||||
/* Handle remaining entries later */
|
||||
if (!list_empty(&ehci->intr_unlink)) {
|
||||
ehci_enable_event(ehci, EHCI_HRTIMER_UNLINK_INTR, true);
|
||||
++ehci->intr_unlink_cycle;
|
||||
}
|
||||
ehci->intr_unlinking = false;
|
||||
}
|
||||
|
||||
|
||||
/* Start another free-iTDs/siTDs cycle */
|
||||
static void start_free_itds(struct ehci_hcd *ehci)
|
||||
{
|
||||
if (!(ehci->enabled_hrtimer_events & BIT(EHCI_HRTIMER_FREE_ITDS))) {
|
||||
ehci->last_itd_to_free = list_entry(
|
||||
ehci->cached_itd_list.prev,
|
||||
struct ehci_itd, itd_list);
|
||||
ehci->last_sitd_to_free = list_entry(
|
||||
ehci->cached_sitd_list.prev,
|
||||
struct ehci_sitd, sitd_list);
|
||||
ehci_enable_event(ehci, EHCI_HRTIMER_FREE_ITDS, true);
|
||||
}
|
||||
}
|
||||
|
||||
/* Wait for controller to stop using old iTDs and siTDs */
|
||||
static void end_free_itds(struct ehci_hcd *ehci)
|
||||
{
|
||||
struct ehci_itd *itd, *n;
|
||||
struct ehci_sitd *sitd, *sn;
|
||||
|
||||
if (ehci->rh_state < EHCI_RH_RUNNING) {
|
||||
ehci->last_itd_to_free = NULL;
|
||||
ehci->last_sitd_to_free = NULL;
|
||||
}
|
||||
|
||||
list_for_each_entry_safe(itd, n, &ehci->cached_itd_list, itd_list) {
|
||||
list_del(&itd->itd_list);
|
||||
dma_pool_free(ehci->itd_pool, itd, itd->itd_dma);
|
||||
if (itd == ehci->last_itd_to_free)
|
||||
break;
|
||||
}
|
||||
list_for_each_entry_safe(sitd, sn, &ehci->cached_sitd_list, sitd_list) {
|
||||
list_del(&sitd->sitd_list);
|
||||
dma_pool_free(ehci->sitd_pool, sitd, sitd->sitd_dma);
|
||||
if (sitd == ehci->last_sitd_to_free)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!list_empty(&ehci->cached_itd_list) ||
|
||||
!list_empty(&ehci->cached_sitd_list))
|
||||
start_free_itds(ehci);
|
||||
}
|
||||
|
||||
|
||||
/* Handle lost (or very late) IAA interrupts */
|
||||
static void ehci_iaa_watchdog(struct ehci_hcd *ehci)
|
||||
{
|
||||
u32 cmd, status;
|
||||
|
||||
/*
|
||||
* Lost IAA irqs wedge things badly; seen first with a vt8235.
|
||||
* So we need this watchdog, but must protect it against both
|
||||
* (a) SMP races against real IAA firing and retriggering, and
|
||||
* (b) clean HC shutdown, when IAA watchdog was pending.
|
||||
*/
|
||||
if (!ehci->iaa_in_progress || ehci->rh_state != EHCI_RH_RUNNING)
|
||||
return;
|
||||
|
||||
/* If we get here, IAA is *REALLY* late. It's barely
|
||||
* conceivable that the system is so busy that CMD_IAAD
|
||||
* is still legitimately set, so let's be sure it's
|
||||
* clear before we read STS_IAA. (The HC should clear
|
||||
* CMD_IAAD when it sets STS_IAA.)
|
||||
*/
|
||||
cmd = ehci_readl(ehci, &ehci->regs->command);
|
||||
|
||||
/*
|
||||
* If IAA is set here it either legitimately triggered
|
||||
* after the watchdog timer expired (_way_ late, so we'll
|
||||
* still count it as lost) ... or a silicon erratum:
|
||||
* - VIA seems to set IAA without triggering the IRQ;
|
||||
* - IAAD potentially cleared without setting IAA.
|
||||
*/
|
||||
status = ehci_readl(ehci, &ehci->regs->status);
|
||||
if ((status & STS_IAA) || !(cmd & CMD_IAAD)) {
|
||||
COUNT(ehci->stats.lost_iaa);
|
||||
ehci_writel(ehci, STS_IAA, &ehci->regs->status);
|
||||
}
|
||||
|
||||
ehci_dbg(ehci, "IAA watchdog: status %x cmd %x\n", status, cmd);
|
||||
end_unlink_async(ehci);
|
||||
}
|
||||
|
||||
|
||||
/* Enable the I/O watchdog, if appropriate */
|
||||
static void turn_on_io_watchdog(struct ehci_hcd *ehci)
|
||||
{
|
||||
/* Not needed if the controller isn't running or it's already enabled */
|
||||
if (ehci->rh_state != EHCI_RH_RUNNING ||
|
||||
(ehci->enabled_hrtimer_events &
|
||||
BIT(EHCI_HRTIMER_IO_WATCHDOG)))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Isochronous transfers always need the watchdog.
|
||||
* For other sorts we use it only if the flag is set.
|
||||
*/
|
||||
if (ehci->isoc_count > 0 || (ehci->need_io_watchdog &&
|
||||
ehci->async_count + ehci->intr_count > 0))
|
||||
ehci_enable_event(ehci, EHCI_HRTIMER_IO_WATCHDOG, true);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Handler functions for the hrtimer event types.
|
||||
* Keep this array in the same order as the event types indexed by
|
||||
* enum ehci_hrtimer_event in ehci.h.
|
||||
*/
|
||||
static void (*event_handlers[])(struct ehci_hcd *) = {
|
||||
ehci_poll_ASS, /* EHCI_HRTIMER_POLL_ASS */
|
||||
ehci_poll_PSS, /* EHCI_HRTIMER_POLL_PSS */
|
||||
ehci_handle_controller_death, /* EHCI_HRTIMER_POLL_DEAD */
|
||||
ehci_handle_intr_unlinks, /* EHCI_HRTIMER_UNLINK_INTR */
|
||||
end_free_itds, /* EHCI_HRTIMER_FREE_ITDS */
|
||||
unlink_empty_async, /* EHCI_HRTIMER_ASYNC_UNLINKS */
|
||||
ehci_iaa_watchdog, /* EHCI_HRTIMER_IAA_WATCHDOG */
|
||||
ehci_disable_PSE, /* EHCI_HRTIMER_DISABLE_PERIODIC */
|
||||
ehci_disable_ASE, /* EHCI_HRTIMER_DISABLE_ASYNC */
|
||||
ehci_work, /* EHCI_HRTIMER_IO_WATCHDOG */
|
||||
};
|
||||
|
||||
static enum hrtimer_restart ehci_hrtimer_func(struct hrtimer *t)
|
||||
{
|
||||
struct ehci_hcd *ehci = container_of(t, struct ehci_hcd, hrtimer);
|
||||
ktime_t now;
|
||||
unsigned long events;
|
||||
unsigned long flags;
|
||||
unsigned e;
|
||||
|
||||
spin_lock_irqsave(&ehci->lock, flags);
|
||||
|
||||
events = ehci->enabled_hrtimer_events;
|
||||
ehci->enabled_hrtimer_events = 0;
|
||||
ehci->next_hrtimer_event = EHCI_HRTIMER_NO_EVENT;
|
||||
|
||||
/*
|
||||
* Check each pending event. If its time has expired, handle
|
||||
* the event; otherwise re-enable it.
|
||||
*/
|
||||
now = ktime_get();
|
||||
for_each_set_bit(e, &events, EHCI_HRTIMER_NUM_EVENTS) {
|
||||
if (now.tv64 >= ehci->hr_timeouts[e].tv64)
|
||||
event_handlers[e](ehci);
|
||||
else
|
||||
ehci_enable_event(ehci, e, false);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&ehci->lock, flags);
|
||||
return HRTIMER_NORESTART;
|
||||
}
|
||||
825
addons/ehci-pci/src/3.10.108/ehci.h
Normal file
825
addons/ehci-pci/src/3.10.108/ehci.h
Normal file
@@ -0,0 +1,825 @@
|
||||
/*
|
||||
* Copyright (c) 2001-2002 by David Brownell
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_EHCI_HCD_H
|
||||
#define __LINUX_EHCI_HCD_H
|
||||
|
||||
/* definitions used for the EHCI driver */
|
||||
|
||||
/*
|
||||
* __hc32 and __hc16 are "Host Controller" types, they may be equivalent to
|
||||
* __leXX (normally) or __beXX (given EHCI_BIG_ENDIAN_DESC), depending on
|
||||
* the host controller implementation.
|
||||
*
|
||||
* To facilitate the strongest possible byte-order checking from "sparse"
|
||||
* and so on, we use __leXX unless that's not practical.
|
||||
*/
|
||||
#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_DESC
|
||||
typedef __u32 __bitwise __hc32;
|
||||
typedef __u16 __bitwise __hc16;
|
||||
#else
|
||||
#define __hc32 __le32
|
||||
#define __hc16 __le16
|
||||
#endif
|
||||
|
||||
/* statistics can be kept for tuning/monitoring */
|
||||
#ifdef DEBUG
|
||||
#define EHCI_STATS
|
||||
#endif
|
||||
|
||||
struct ehci_stats {
|
||||
/* irq usage */
|
||||
unsigned long normal;
|
||||
unsigned long error;
|
||||
unsigned long iaa;
|
||||
unsigned long lost_iaa;
|
||||
|
||||
/* termination of urbs from core */
|
||||
unsigned long complete;
|
||||
unsigned long unlink;
|
||||
};
|
||||
|
||||
/* ehci_hcd->lock guards shared data against other CPUs:
|
||||
* ehci_hcd: async, unlink, periodic (and shadow), ...
|
||||
* usb_host_endpoint: hcpriv
|
||||
* ehci_qh: qh_next, qtd_list
|
||||
* ehci_qtd: qtd_list
|
||||
*
|
||||
* Also, hold this lock when talking to HC registers or
|
||||
* when updating hw_* fields in shared qh/qtd/... structures.
|
||||
*/
|
||||
|
||||
#define EHCI_MAX_ROOT_PORTS 15 /* see HCS_N_PORTS */
|
||||
|
||||
/*
|
||||
* ehci_rh_state values of EHCI_RH_RUNNING or above mean that the
|
||||
* controller may be doing DMA. Lower values mean there's no DMA.
|
||||
*/
|
||||
enum ehci_rh_state {
|
||||
EHCI_RH_HALTED,
|
||||
EHCI_RH_SUSPENDED,
|
||||
EHCI_RH_RUNNING,
|
||||
EHCI_RH_STOPPING
|
||||
};
|
||||
|
||||
/*
|
||||
* Timer events, ordered by increasing delay length.
|
||||
* Always update event_delays_ns[] and event_handlers[] (defined in
|
||||
* ehci-timer.c) in parallel with this list.
|
||||
*/
|
||||
enum ehci_hrtimer_event {
|
||||
EHCI_HRTIMER_POLL_ASS, /* Poll for async schedule off */
|
||||
EHCI_HRTIMER_POLL_PSS, /* Poll for periodic schedule off */
|
||||
EHCI_HRTIMER_POLL_DEAD, /* Wait for dead controller to stop */
|
||||
EHCI_HRTIMER_UNLINK_INTR, /* Wait for interrupt QH unlink */
|
||||
EHCI_HRTIMER_FREE_ITDS, /* Wait for unused iTDs and siTDs */
|
||||
EHCI_HRTIMER_ASYNC_UNLINKS, /* Unlink empty async QHs */
|
||||
EHCI_HRTIMER_IAA_WATCHDOG, /* Handle lost IAA interrupts */
|
||||
EHCI_HRTIMER_DISABLE_PERIODIC, /* Wait to disable periodic sched */
|
||||
EHCI_HRTIMER_DISABLE_ASYNC, /* Wait to disable async sched */
|
||||
EHCI_HRTIMER_IO_WATCHDOG, /* Check for missing IRQs */
|
||||
EHCI_HRTIMER_NUM_EVENTS /* Must come last */
|
||||
};
|
||||
#define EHCI_HRTIMER_NO_EVENT 99
|
||||
|
||||
struct ehci_hcd { /* one per controller */
|
||||
/* timing support */
|
||||
enum ehci_hrtimer_event next_hrtimer_event;
|
||||
unsigned enabled_hrtimer_events;
|
||||
ktime_t hr_timeouts[EHCI_HRTIMER_NUM_EVENTS];
|
||||
struct hrtimer hrtimer;
|
||||
|
||||
int PSS_poll_count;
|
||||
int ASS_poll_count;
|
||||
int died_poll_count;
|
||||
|
||||
/* glue to PCI and HCD framework */
|
||||
struct ehci_caps __iomem *caps;
|
||||
struct ehci_regs __iomem *regs;
|
||||
struct ehci_dbg_port __iomem *debug;
|
||||
|
||||
__u32 hcs_params; /* cached register copy */
|
||||
spinlock_t lock;
|
||||
enum ehci_rh_state rh_state;
|
||||
|
||||
/* general schedule support */
|
||||
bool scanning:1;
|
||||
bool need_rescan:1;
|
||||
bool intr_unlinking:1;
|
||||
bool iaa_in_progress:1;
|
||||
bool async_unlinking:1;
|
||||
bool shutdown:1;
|
||||
struct ehci_qh *qh_scan_next;
|
||||
|
||||
/* async schedule support */
|
||||
struct ehci_qh *async;
|
||||
struct ehci_qh *dummy; /* For AMD quirk use */
|
||||
struct list_head async_unlink;
|
||||
struct list_head async_idle;
|
||||
unsigned async_unlink_cycle;
|
||||
unsigned async_count; /* async activity count */
|
||||
|
||||
/* periodic schedule support */
|
||||
#define DEFAULT_I_TDPS 1024 /* some HCs can do less */
|
||||
unsigned periodic_size;
|
||||
__hc32 *periodic; /* hw periodic table */
|
||||
dma_addr_t periodic_dma;
|
||||
struct list_head intr_qh_list;
|
||||
unsigned i_thresh; /* uframes HC might cache */
|
||||
|
||||
union ehci_shadow *pshadow; /* mirror hw periodic table */
|
||||
struct list_head intr_unlink;
|
||||
unsigned intr_unlink_cycle;
|
||||
unsigned now_frame; /* frame from HC hardware */
|
||||
unsigned last_iso_frame; /* last frame scanned for iso */
|
||||
unsigned intr_count; /* intr activity count */
|
||||
unsigned isoc_count; /* isoc activity count */
|
||||
unsigned periodic_count; /* periodic activity count */
|
||||
unsigned uframe_periodic_max; /* max periodic time per uframe */
|
||||
|
||||
|
||||
/* list of itds & sitds completed while now_frame was still active */
|
||||
struct list_head cached_itd_list;
|
||||
struct ehci_itd *last_itd_to_free;
|
||||
struct list_head cached_sitd_list;
|
||||
struct ehci_sitd *last_sitd_to_free;
|
||||
|
||||
/* per root hub port */
|
||||
unsigned long reset_done [EHCI_MAX_ROOT_PORTS];
|
||||
|
||||
/* bit vectors (one bit per port) */
|
||||
unsigned long bus_suspended; /* which ports were
|
||||
already suspended at the start of a bus suspend */
|
||||
unsigned long companion_ports; /* which ports are
|
||||
dedicated to the companion controller */
|
||||
unsigned long owned_ports; /* which ports are
|
||||
owned by the companion during a bus suspend */
|
||||
unsigned long port_c_suspend; /* which ports have
|
||||
the change-suspend feature turned on */
|
||||
unsigned long suspended_ports; /* which ports are
|
||||
suspended */
|
||||
unsigned long resuming_ports; /* which ports have
|
||||
started to resume */
|
||||
|
||||
/* per-HC memory pools (could be per-bus, but ...) */
|
||||
struct dma_pool *qh_pool; /* qh per active urb */
|
||||
struct dma_pool *qtd_pool; /* one or more per qh */
|
||||
struct dma_pool *itd_pool; /* itd per iso urb */
|
||||
struct dma_pool *sitd_pool; /* sitd per split iso urb */
|
||||
|
||||
unsigned random_frame;
|
||||
unsigned long next_statechange;
|
||||
ktime_t last_periodic_enable;
|
||||
u32 command;
|
||||
|
||||
/* SILICON QUIRKS */
|
||||
unsigned no_selective_suspend:1;
|
||||
unsigned has_fsl_port_bug:1; /* FreeScale */
|
||||
unsigned big_endian_mmio:1;
|
||||
unsigned big_endian_desc:1;
|
||||
unsigned big_endian_capbase:1;
|
||||
unsigned has_amcc_usb23:1;
|
||||
unsigned need_io_watchdog:1;
|
||||
unsigned amd_pll_fix:1;
|
||||
unsigned use_dummy_qh:1; /* AMD Frame List table quirk*/
|
||||
unsigned has_synopsys_hc_bug:1; /* Synopsys HC */
|
||||
unsigned frame_index_bug:1; /* MosChip (AKA NetMos) */
|
||||
unsigned need_oc_pp_cycle:1; /* MPC834X port power */
|
||||
unsigned imx28_write_fix:1; /* For Freescale i.MX28 */
|
||||
|
||||
/* required for usb32 quirk */
|
||||
#define OHCI_CTRL_HCFS (3 << 6)
|
||||
#define OHCI_USB_OPER (2 << 6)
|
||||
#define OHCI_USB_SUSPEND (3 << 6)
|
||||
|
||||
#define OHCI_HCCTRL_OFFSET 0x4
|
||||
#define OHCI_HCCTRL_LEN 0x4
|
||||
__hc32 *ohci_hcctrl_reg;
|
||||
unsigned has_hostpc:1;
|
||||
unsigned has_ppcd:1; /* support per-port change bits */
|
||||
u8 sbrn; /* packed release number */
|
||||
|
||||
/* irq statistics */
|
||||
#ifdef EHCI_STATS
|
||||
struct ehci_stats stats;
|
||||
# define COUNT(x) do { (x)++; } while (0)
|
||||
#else
|
||||
# define COUNT(x) do {} while (0)
|
||||
#endif
|
||||
|
||||
/* debug files */
|
||||
#ifdef DEBUG
|
||||
struct dentry *debug_dir;
|
||||
#endif
|
||||
|
||||
/* platform-specific data -- must come last */
|
||||
unsigned long priv[0] __aligned(sizeof(s64));
|
||||
};
|
||||
|
||||
/* convert between an HCD pointer and the corresponding EHCI_HCD */
|
||||
static inline struct ehci_hcd *hcd_to_ehci (struct usb_hcd *hcd)
|
||||
{
|
||||
return (struct ehci_hcd *) (hcd->hcd_priv);
|
||||
}
|
||||
static inline struct usb_hcd *ehci_to_hcd (struct ehci_hcd *ehci)
|
||||
{
|
||||
return container_of ((void *) ehci, struct usb_hcd, hcd_priv);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
#include <linux/usb/ehci_def.h>
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
#define QTD_NEXT(ehci, dma) cpu_to_hc32(ehci, (u32)dma)
|
||||
|
||||
/*
|
||||
* EHCI Specification 0.95 Section 3.5
|
||||
* QTD: describe data transfer components (buffer, direction, ...)
|
||||
* See Fig 3-6 "Queue Element Transfer Descriptor Block Diagram".
|
||||
*
|
||||
* These are associated only with "QH" (Queue Head) structures,
|
||||
* used with control, bulk, and interrupt transfers.
|
||||
*/
|
||||
struct ehci_qtd {
|
||||
/* first part defined by EHCI spec */
|
||||
__hc32 hw_next; /* see EHCI 3.5.1 */
|
||||
__hc32 hw_alt_next; /* see EHCI 3.5.2 */
|
||||
__hc32 hw_token; /* see EHCI 3.5.3 */
|
||||
#define QTD_TOGGLE (1 << 31) /* data toggle */
|
||||
#define QTD_LENGTH(tok) (((tok)>>16) & 0x7fff)
|
||||
#define QTD_IOC (1 << 15) /* interrupt on complete */
|
||||
#define QTD_CERR(tok) (((tok)>>10) & 0x3)
|
||||
#define QTD_PID(tok) (((tok)>>8) & 0x3)
|
||||
#define QTD_STS_ACTIVE (1 << 7) /* HC may execute this */
|
||||
#define QTD_STS_HALT (1 << 6) /* halted on error */
|
||||
#define QTD_STS_DBE (1 << 5) /* data buffer error (in HC) */
|
||||
#define QTD_STS_BABBLE (1 << 4) /* device was babbling (qtd halted) */
|
||||
#define QTD_STS_XACT (1 << 3) /* device gave illegal response */
|
||||
#define QTD_STS_MMF (1 << 2) /* incomplete split transaction */
|
||||
#define QTD_STS_STS (1 << 1) /* split transaction state */
|
||||
#define QTD_STS_PING (1 << 0) /* issue PING? */
|
||||
|
||||
#define ACTIVE_BIT(ehci) cpu_to_hc32(ehci, QTD_STS_ACTIVE)
|
||||
#define HALT_BIT(ehci) cpu_to_hc32(ehci, QTD_STS_HALT)
|
||||
#define STATUS_BIT(ehci) cpu_to_hc32(ehci, QTD_STS_STS)
|
||||
|
||||
__hc32 hw_buf [5]; /* see EHCI 3.5.4 */
|
||||
__hc32 hw_buf_hi [5]; /* Appendix B */
|
||||
|
||||
/* the rest is HCD-private */
|
||||
dma_addr_t qtd_dma; /* qtd address */
|
||||
struct list_head qtd_list; /* sw qtd list */
|
||||
struct urb *urb; /* qtd's urb */
|
||||
size_t length; /* length of buffer */
|
||||
} __attribute__ ((aligned (32)));
|
||||
|
||||
/* mask NakCnt+T in qh->hw_alt_next */
|
||||
#define QTD_MASK(ehci) cpu_to_hc32 (ehci, ~0x1f)
|
||||
|
||||
#define IS_SHORT_READ(token) (QTD_LENGTH (token) != 0 && QTD_PID (token) == 1)
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* type tag from {qh,itd,sitd,fstn}->hw_next */
|
||||
#define Q_NEXT_TYPE(ehci,dma) ((dma) & cpu_to_hc32(ehci, 3 << 1))
|
||||
|
||||
/*
|
||||
* Now the following defines are not converted using the
|
||||
* cpu_to_le32() macro anymore, since we have to support
|
||||
* "dynamic" switching between be and le support, so that the driver
|
||||
* can be used on one system with SoC EHCI controller using big-endian
|
||||
* descriptors as well as a normal little-endian PCI EHCI controller.
|
||||
*/
|
||||
/* values for that type tag */
|
||||
#define Q_TYPE_ITD (0 << 1)
|
||||
#define Q_TYPE_QH (1 << 1)
|
||||
#define Q_TYPE_SITD (2 << 1)
|
||||
#define Q_TYPE_FSTN (3 << 1)
|
||||
|
||||
/* next async queue entry, or pointer to interrupt/periodic QH */
|
||||
#define QH_NEXT(ehci,dma) (cpu_to_hc32(ehci, (((u32)dma)&~0x01f)|Q_TYPE_QH))
|
||||
|
||||
/* for periodic/async schedules and qtd lists, mark end of list */
|
||||
#define EHCI_LIST_END(ehci) cpu_to_hc32(ehci, 1) /* "null pointer" to hw */
|
||||
|
||||
/*
|
||||
* Entries in periodic shadow table are pointers to one of four kinds
|
||||
* of data structure. That's dictated by the hardware; a type tag is
|
||||
* encoded in the low bits of the hardware's periodic schedule. Use
|
||||
* Q_NEXT_TYPE to get the tag.
|
||||
*
|
||||
* For entries in the async schedule, the type tag always says "qh".
|
||||
*/
|
||||
union ehci_shadow {
|
||||
struct ehci_qh *qh; /* Q_TYPE_QH */
|
||||
struct ehci_itd *itd; /* Q_TYPE_ITD */
|
||||
struct ehci_sitd *sitd; /* Q_TYPE_SITD */
|
||||
struct ehci_fstn *fstn; /* Q_TYPE_FSTN */
|
||||
__hc32 *hw_next; /* (all types) */
|
||||
void *ptr;
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* EHCI Specification 0.95 Section 3.6
|
||||
* QH: describes control/bulk/interrupt endpoints
|
||||
* See Fig 3-7 "Queue Head Structure Layout".
|
||||
*
|
||||
* These appear in both the async and (for interrupt) periodic schedules.
|
||||
*/
|
||||
|
||||
/* first part defined by EHCI spec */
|
||||
struct ehci_qh_hw {
|
||||
__hc32 hw_next; /* see EHCI 3.6.1 */
|
||||
__hc32 hw_info1; /* see EHCI 3.6.2 */
|
||||
#define QH_CONTROL_EP (1 << 27) /* FS/LS control endpoint */
|
||||
#define QH_HEAD (1 << 15) /* Head of async reclamation list */
|
||||
#define QH_TOGGLE_CTL (1 << 14) /* Data toggle control */
|
||||
#define QH_HIGH_SPEED (2 << 12) /* Endpoint speed */
|
||||
#define QH_LOW_SPEED (1 << 12)
|
||||
#define QH_FULL_SPEED (0 << 12)
|
||||
#define QH_INACTIVATE (1 << 7) /* Inactivate on next transaction */
|
||||
__hc32 hw_info2; /* see EHCI 3.6.2 */
|
||||
#define QH_SMASK 0x000000ff
|
||||
#define QH_CMASK 0x0000ff00
|
||||
#define QH_HUBADDR 0x007f0000
|
||||
#define QH_HUBPORT 0x3f800000
|
||||
#define QH_MULT 0xc0000000
|
||||
__hc32 hw_current; /* qtd list - see EHCI 3.6.4 */
|
||||
|
||||
/* qtd overlay (hardware parts of a struct ehci_qtd) */
|
||||
__hc32 hw_qtd_next;
|
||||
__hc32 hw_alt_next;
|
||||
__hc32 hw_token;
|
||||
__hc32 hw_buf [5];
|
||||
__hc32 hw_buf_hi [5];
|
||||
} __attribute__ ((aligned(32)));
|
||||
|
||||
struct ehci_qh {
|
||||
struct ehci_qh_hw *hw; /* Must come first */
|
||||
/* the rest is HCD-private */
|
||||
dma_addr_t qh_dma; /* address of qh */
|
||||
union ehci_shadow qh_next; /* ptr to qh; or periodic */
|
||||
struct list_head qtd_list; /* sw qtd list */
|
||||
struct list_head intr_node; /* list of intr QHs */
|
||||
struct ehci_qtd *dummy;
|
||||
struct list_head unlink_node;
|
||||
|
||||
unsigned unlink_cycle;
|
||||
|
||||
u8 qh_state;
|
||||
#define QH_STATE_LINKED 1 /* HC sees this */
|
||||
#define QH_STATE_UNLINK 2 /* HC may still see this */
|
||||
#define QH_STATE_IDLE 3 /* HC doesn't see this */
|
||||
#define QH_STATE_UNLINK_WAIT 4 /* LINKED and on unlink q */
|
||||
#define QH_STATE_COMPLETING 5 /* don't touch token.HALT */
|
||||
|
||||
u8 xacterrs; /* XactErr retry counter */
|
||||
#define QH_XACTERR_MAX 32 /* XactErr retry limit */
|
||||
|
||||
/* periodic schedule info */
|
||||
u8 usecs; /* intr bandwidth */
|
||||
u8 gap_uf; /* uframes split/csplit gap */
|
||||
u8 c_usecs; /* ... split completion bw */
|
||||
u16 tt_usecs; /* tt downstream bandwidth */
|
||||
unsigned short period; /* polling interval */
|
||||
unsigned short start; /* where polling starts */
|
||||
#define NO_FRAME ((unsigned short)~0) /* pick new start */
|
||||
|
||||
struct usb_device *dev; /* access to TT */
|
||||
unsigned is_out:1; /* bulk or intr OUT */
|
||||
unsigned clearing_tt:1; /* Clear-TT-Buf in progress */
|
||||
unsigned dequeue_during_giveback:1;
|
||||
unsigned exception:1; /* got a fault, or an unlink
|
||||
was requested */
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* description of one iso transaction (up to 3 KB data if highspeed) */
|
||||
struct ehci_iso_packet {
|
||||
/* These will be copied to iTD when scheduling */
|
||||
u64 bufp; /* itd->hw_bufp{,_hi}[pg] |= */
|
||||
__hc32 transaction; /* itd->hw_transaction[i] |= */
|
||||
u8 cross; /* buf crosses pages */
|
||||
/* for full speed OUT splits */
|
||||
u32 buf1;
|
||||
};
|
||||
|
||||
/* temporary schedule data for packets from iso urbs (both speeds)
|
||||
* each packet is one logical usb transaction to the device (not TT),
|
||||
* beginning at stream->next_uframe
|
||||
*/
|
||||
struct ehci_iso_sched {
|
||||
struct list_head td_list;
|
||||
unsigned span;
|
||||
struct ehci_iso_packet packet [0];
|
||||
};
|
||||
|
||||
/*
|
||||
* ehci_iso_stream - groups all (s)itds for this endpoint.
|
||||
* acts like a qh would, if EHCI had them for ISO.
|
||||
*/
|
||||
struct ehci_iso_stream {
|
||||
/* first field matches ehci_hq, but is NULL */
|
||||
struct ehci_qh_hw *hw;
|
||||
|
||||
u8 bEndpointAddress;
|
||||
u8 highspeed;
|
||||
struct list_head td_list; /* queued itds/sitds */
|
||||
struct list_head free_list; /* list of unused itds/sitds */
|
||||
struct usb_device *udev;
|
||||
struct usb_host_endpoint *ep;
|
||||
|
||||
/* output of (re)scheduling */
|
||||
int next_uframe;
|
||||
__hc32 splits;
|
||||
|
||||
/* the rest is derived from the endpoint descriptor,
|
||||
* trusting urb->interval == f(epdesc->bInterval) and
|
||||
* including the extra info for hw_bufp[0..2]
|
||||
*/
|
||||
u8 usecs, c_usecs;
|
||||
u16 interval;
|
||||
u16 tt_usecs;
|
||||
u16 maxp;
|
||||
u16 raw_mask;
|
||||
unsigned bandwidth;
|
||||
|
||||
/* This is used to initialize iTD's hw_bufp fields */
|
||||
__hc32 buf0;
|
||||
__hc32 buf1;
|
||||
__hc32 buf2;
|
||||
|
||||
/* this is used to initialize sITD's tt info */
|
||||
__hc32 address;
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* EHCI Specification 0.95 Section 3.3
|
||||
* Fig 3-4 "Isochronous Transaction Descriptor (iTD)"
|
||||
*
|
||||
* Schedule records for high speed iso xfers
|
||||
*/
|
||||
struct ehci_itd {
|
||||
/* first part defined by EHCI spec */
|
||||
__hc32 hw_next; /* see EHCI 3.3.1 */
|
||||
__hc32 hw_transaction [8]; /* see EHCI 3.3.2 */
|
||||
#define EHCI_ISOC_ACTIVE (1<<31) /* activate transfer this slot */
|
||||
#define EHCI_ISOC_BUF_ERR (1<<30) /* Data buffer error */
|
||||
#define EHCI_ISOC_BABBLE (1<<29) /* babble detected */
|
||||
#define EHCI_ISOC_XACTERR (1<<28) /* XactErr - transaction error */
|
||||
#define EHCI_ITD_LENGTH(tok) (((tok)>>16) & 0x0fff)
|
||||
#define EHCI_ITD_IOC (1 << 15) /* interrupt on complete */
|
||||
|
||||
#define ITD_ACTIVE(ehci) cpu_to_hc32(ehci, EHCI_ISOC_ACTIVE)
|
||||
|
||||
__hc32 hw_bufp [7]; /* see EHCI 3.3.3 */
|
||||
__hc32 hw_bufp_hi [7]; /* Appendix B */
|
||||
|
||||
/* the rest is HCD-private */
|
||||
dma_addr_t itd_dma; /* for this itd */
|
||||
union ehci_shadow itd_next; /* ptr to periodic q entry */
|
||||
|
||||
struct urb *urb;
|
||||
struct ehci_iso_stream *stream; /* endpoint's queue */
|
||||
struct list_head itd_list; /* list of stream's itds */
|
||||
|
||||
/* any/all hw_transactions here may be used by that urb */
|
||||
unsigned frame; /* where scheduled */
|
||||
unsigned pg;
|
||||
unsigned index[8]; /* in urb->iso_frame_desc */
|
||||
} __attribute__ ((aligned (32)));
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* EHCI Specification 0.95 Section 3.4
|
||||
* siTD, aka split-transaction isochronous Transfer Descriptor
|
||||
* ... describe full speed iso xfers through TT in hubs
|
||||
* see Figure 3-5 "Split-transaction Isochronous Transaction Descriptor (siTD)
|
||||
*/
|
||||
struct ehci_sitd {
|
||||
/* first part defined by EHCI spec */
|
||||
__hc32 hw_next;
|
||||
/* uses bit field macros above - see EHCI 0.95 Table 3-8 */
|
||||
__hc32 hw_fullspeed_ep; /* EHCI table 3-9 */
|
||||
__hc32 hw_uframe; /* EHCI table 3-10 */
|
||||
__hc32 hw_results; /* EHCI table 3-11 */
|
||||
#define SITD_IOC (1 << 31) /* interrupt on completion */
|
||||
#define SITD_PAGE (1 << 30) /* buffer 0/1 */
|
||||
#define SITD_LENGTH(x) (0x3ff & ((x)>>16))
|
||||
#define SITD_STS_ACTIVE (1 << 7) /* HC may execute this */
|
||||
#define SITD_STS_ERR (1 << 6) /* error from TT */
|
||||
#define SITD_STS_DBE (1 << 5) /* data buffer error (in HC) */
|
||||
#define SITD_STS_BABBLE (1 << 4) /* device was babbling */
|
||||
#define SITD_STS_XACT (1 << 3) /* illegal IN response */
|
||||
#define SITD_STS_MMF (1 << 2) /* incomplete split transaction */
|
||||
#define SITD_STS_STS (1 << 1) /* split transaction state */
|
||||
|
||||
#define SITD_ACTIVE(ehci) cpu_to_hc32(ehci, SITD_STS_ACTIVE)
|
||||
|
||||
__hc32 hw_buf [2]; /* EHCI table 3-12 */
|
||||
__hc32 hw_backpointer; /* EHCI table 3-13 */
|
||||
__hc32 hw_buf_hi [2]; /* Appendix B */
|
||||
|
||||
/* the rest is HCD-private */
|
||||
dma_addr_t sitd_dma;
|
||||
union ehci_shadow sitd_next; /* ptr to periodic q entry */
|
||||
|
||||
struct urb *urb;
|
||||
struct ehci_iso_stream *stream; /* endpoint's queue */
|
||||
struct list_head sitd_list; /* list of stream's sitds */
|
||||
unsigned frame;
|
||||
unsigned index;
|
||||
} __attribute__ ((aligned (32)));
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* EHCI Specification 0.96 Section 3.7
|
||||
* Periodic Frame Span Traversal Node (FSTN)
|
||||
*
|
||||
* Manages split interrupt transactions (using TT) that span frame boundaries
|
||||
* into uframes 0/1; see 4.12.2.2. In those uframes, a "save place" FSTN
|
||||
* makes the HC jump (back) to a QH to scan for fs/ls QH completions until
|
||||
* it hits a "restore" FSTN; then it returns to finish other uframe 0/1 work.
|
||||
*/
|
||||
struct ehci_fstn {
|
||||
__hc32 hw_next; /* any periodic q entry */
|
||||
__hc32 hw_prev; /* qh or EHCI_LIST_END */
|
||||
|
||||
/* the rest is HCD-private */
|
||||
dma_addr_t fstn_dma;
|
||||
union ehci_shadow fstn_next; /* ptr to periodic q entry */
|
||||
} __attribute__ ((aligned (32)));
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* Prepare the PORTSC wakeup flags during controller suspend/resume */
|
||||
|
||||
#define ehci_prepare_ports_for_controller_suspend(ehci, do_wakeup) \
|
||||
ehci_adjust_port_wakeup_flags(ehci, true, do_wakeup);
|
||||
|
||||
#define ehci_prepare_ports_for_controller_resume(ehci) \
|
||||
ehci_adjust_port_wakeup_flags(ehci, false, false);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
#ifdef CONFIG_USB_EHCI_ROOT_HUB_TT
|
||||
|
||||
/*
|
||||
* Some EHCI controllers have a Transaction Translator built into the
|
||||
* root hub. This is a non-standard feature. Each controller will need
|
||||
* to add code to the following inline functions, and call them as
|
||||
* needed (mostly in root hub code).
|
||||
*/
|
||||
|
||||
#define ehci_is_TDI(e) (ehci_to_hcd(e)->has_tt)
|
||||
|
||||
/* Returns the speed of a device attached to a port on the root hub. */
|
||||
static inline unsigned int
|
||||
ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
|
||||
{
|
||||
if (ehci_is_TDI(ehci)) {
|
||||
switch ((portsc >> (ehci->has_hostpc ? 25 : 26)) & 3) {
|
||||
case 0:
|
||||
return 0;
|
||||
case 1:
|
||||
return USB_PORT_STAT_LOW_SPEED;
|
||||
case 2:
|
||||
default:
|
||||
return USB_PORT_STAT_HIGH_SPEED;
|
||||
}
|
||||
}
|
||||
return USB_PORT_STAT_HIGH_SPEED;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define ehci_is_TDI(e) (0)
|
||||
|
||||
#define ehci_port_speed(ehci, portsc) USB_PORT_STAT_HIGH_SPEED
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
#ifdef CONFIG_PPC_83xx
|
||||
/* Some Freescale processors have an erratum in which the TT
|
||||
* port number in the queue head was 0..N-1 instead of 1..N.
|
||||
*/
|
||||
#define ehci_has_fsl_portno_bug(e) ((e)->has_fsl_port_bug)
|
||||
#else
|
||||
#define ehci_has_fsl_portno_bug(e) (0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* While most USB host controllers implement their registers in
|
||||
* little-endian format, a minority (celleb companion chip) implement
|
||||
* them in big endian format.
|
||||
*
|
||||
* This attempts to support either format at compile time without a
|
||||
* runtime penalty, or both formats with the additional overhead
|
||||
* of checking a flag bit.
|
||||
*
|
||||
* ehci_big_endian_capbase is a special quirk for controllers that
|
||||
* implement the HC capability registers as separate registers and not
|
||||
* as fields of a 32-bit register.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
|
||||
#define ehci_big_endian_mmio(e) ((e)->big_endian_mmio)
|
||||
#define ehci_big_endian_capbase(e) ((e)->big_endian_capbase)
|
||||
#else
|
||||
#define ehci_big_endian_mmio(e) 0
|
||||
#define ehci_big_endian_capbase(e) 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Big-endian read/write functions are arch-specific.
|
||||
* Other arches can be added if/when they're needed.
|
||||
*/
|
||||
#if defined(CONFIG_ARM) && defined(CONFIG_ARCH_IXP4XX)
|
||||
#define readl_be(addr) __raw_readl((__force unsigned *)addr)
|
||||
#define writel_be(val, addr) __raw_writel(val, (__force unsigned *)addr)
|
||||
#endif
|
||||
|
||||
static inline unsigned int ehci_readl(const struct ehci_hcd *ehci,
|
||||
__u32 __iomem * regs)
|
||||
{
|
||||
#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
|
||||
return ehci_big_endian_mmio(ehci) ?
|
||||
readl_be(regs) :
|
||||
readl(regs);
|
||||
#else
|
||||
return readl(regs);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SOC_IMX28
|
||||
static inline void imx28_ehci_writel(const unsigned int val,
|
||||
volatile __u32 __iomem *addr)
|
||||
{
|
||||
__asm__ ("swp %0, %0, [%1]" : : "r"(val), "r"(addr));
|
||||
}
|
||||
#else
|
||||
static inline void imx28_ehci_writel(const unsigned int val,
|
||||
volatile __u32 __iomem *addr)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
static inline void ehci_writel(const struct ehci_hcd *ehci,
|
||||
const unsigned int val, __u32 __iomem *regs)
|
||||
{
|
||||
#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
|
||||
ehci_big_endian_mmio(ehci) ?
|
||||
writel_be(val, regs) :
|
||||
writel(val, regs);
|
||||
#else
|
||||
if (ehci->imx28_write_fix)
|
||||
imx28_ehci_writel(val, regs);
|
||||
else
|
||||
writel(val, regs);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* On certain ppc-44x SoC there is a HW issue, that could only worked around with
|
||||
* explicit suspend/operate of OHCI. This function hereby makes sense only on that arch.
|
||||
* Other common bits are dependent on has_amcc_usb23 quirk flag.
|
||||
*/
|
||||
#ifdef CONFIG_44x
|
||||
static inline void set_ohci_hcfs(struct ehci_hcd *ehci, int operational)
|
||||
{
|
||||
u32 hc_control;
|
||||
|
||||
hc_control = (readl_be(ehci->ohci_hcctrl_reg) & ~OHCI_CTRL_HCFS);
|
||||
if (operational)
|
||||
hc_control |= OHCI_USB_OPER;
|
||||
else
|
||||
hc_control |= OHCI_USB_SUSPEND;
|
||||
|
||||
writel_be(hc_control, ehci->ohci_hcctrl_reg);
|
||||
(void) readl_be(ehci->ohci_hcctrl_reg);
|
||||
}
|
||||
#else
|
||||
static inline void set_ohci_hcfs(struct ehci_hcd *ehci, int operational)
|
||||
{ }
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* The AMCC 440EPx not only implements its EHCI registers in big-endian
|
||||
* format, but also its DMA data structures (descriptors).
|
||||
*
|
||||
* EHCI controllers accessed through PCI work normally (little-endian
|
||||
* everywhere), so we won't bother supporting a BE-only mode for now.
|
||||
*/
|
||||
#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_DESC
|
||||
#define ehci_big_endian_desc(e) ((e)->big_endian_desc)
|
||||
|
||||
/* cpu to ehci */
|
||||
static inline __hc32 cpu_to_hc32 (const struct ehci_hcd *ehci, const u32 x)
|
||||
{
|
||||
return ehci_big_endian_desc(ehci)
|
||||
? (__force __hc32)cpu_to_be32(x)
|
||||
: (__force __hc32)cpu_to_le32(x);
|
||||
}
|
||||
|
||||
/* ehci to cpu */
|
||||
static inline u32 hc32_to_cpu (const struct ehci_hcd *ehci, const __hc32 x)
|
||||
{
|
||||
return ehci_big_endian_desc(ehci)
|
||||
? be32_to_cpu((__force __be32)x)
|
||||
: le32_to_cpu((__force __le32)x);
|
||||
}
|
||||
|
||||
static inline u32 hc32_to_cpup (const struct ehci_hcd *ehci, const __hc32 *x)
|
||||
{
|
||||
return ehci_big_endian_desc(ehci)
|
||||
? be32_to_cpup((__force __be32 *)x)
|
||||
: le32_to_cpup((__force __le32 *)x);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* cpu to ehci */
|
||||
static inline __hc32 cpu_to_hc32 (const struct ehci_hcd *ehci, const u32 x)
|
||||
{
|
||||
return cpu_to_le32(x);
|
||||
}
|
||||
|
||||
/* ehci to cpu */
|
||||
static inline u32 hc32_to_cpu (const struct ehci_hcd *ehci, const __hc32 x)
|
||||
{
|
||||
return le32_to_cpu(x);
|
||||
}
|
||||
|
||||
static inline u32 hc32_to_cpup (const struct ehci_hcd *ehci, const __hc32 *x)
|
||||
{
|
||||
return le32_to_cpup(x);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
#define ehci_dbg(ehci, fmt, args...) \
|
||||
dev_dbg(ehci_to_hcd(ehci)->self.controller , fmt , ## args)
|
||||
#define ehci_err(ehci, fmt, args...) \
|
||||
dev_err(ehci_to_hcd(ehci)->self.controller , fmt , ## args)
|
||||
#define ehci_info(ehci, fmt, args...) \
|
||||
dev_info(ehci_to_hcd(ehci)->self.controller , fmt , ## args)
|
||||
#define ehci_warn(ehci, fmt, args...) \
|
||||
dev_warn(ehci_to_hcd(ehci)->self.controller , fmt , ## args)
|
||||
|
||||
#ifdef VERBOSE_DEBUG
|
||||
# define ehci_vdbg ehci_dbg
|
||||
#else
|
||||
static inline void ehci_vdbg(struct ehci_hcd *ehci, ...) {}
|
||||
#endif
|
||||
|
||||
#ifndef DEBUG
|
||||
#define STUB_DEBUG_FILES
|
||||
#endif /* DEBUG */
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* Declarations of things exported for use by ehci platform drivers */
|
||||
|
||||
struct ehci_driver_overrides {
|
||||
size_t extra_priv_size;
|
||||
int (*reset)(struct usb_hcd *hcd);
|
||||
};
|
||||
|
||||
extern void ehci_init_driver(struct hc_driver *drv,
|
||||
const struct ehci_driver_overrides *over);
|
||||
extern int ehci_setup(struct usb_hcd *hcd);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
extern int ehci_suspend(struct usb_hcd *hcd, bool do_wakeup);
|
||||
extern int ehci_resume(struct usb_hcd *hcd, bool hibernated);
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
#endif /* __LINUX_EHCI_HCD_H */
|
||||
1001
addons/ehci-pci/src/3.10.108/pci-quirks.c
Normal file
1001
addons/ehci-pci/src/3.10.108/pci-quirks.c
Normal file
File diff suppressed because it is too large
Load Diff
21
addons/ehci-pci/src/3.10.108/pci-quirks.h
Normal file
21
addons/ehci-pci/src/3.10.108/pci-quirks.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef __LINUX_USB_PCI_QUIRKS_H
|
||||
#define __LINUX_USB_PCI_QUIRKS_H
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
void uhci_reset_hc(struct pci_dev *pdev, unsigned long base);
|
||||
int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base);
|
||||
int usb_amd_find_chipset_info(void);
|
||||
void usb_amd_dev_put(void);
|
||||
void usb_amd_quirk_pll_disable(void);
|
||||
void usb_amd_quirk_pll_enable(void);
|
||||
bool usb_is_intel_switchable_xhci(struct pci_dev *pdev);
|
||||
void usb_enable_xhci_ports(struct pci_dev *xhci_pdev);
|
||||
void usb_disable_xhci_ports(struct pci_dev *xhci_pdev);
|
||||
#else
|
||||
static inline void usb_amd_quirk_pll_disable(void) {}
|
||||
static inline void usb_amd_quirk_pll_enable(void) {}
|
||||
static inline void usb_amd_dev_put(void) {}
|
||||
static inline void usb_disable_xhci_ports(struct pci_dev *xhci_pdev) {}
|
||||
#endif /* CONFIG_PCI */
|
||||
|
||||
#endif /* __LINUX_USB_PCI_QUIRKS_H */
|
||||
155
addons/ehci-pci/src/3.10.108/xhci-ext-caps.h
Normal file
155
addons/ehci-pci/src/3.10.108/xhci-ext-caps.h
Normal file
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* xHCI host controller driver
|
||||
*
|
||||
* Copyright (C) 2008 Intel Corp.
|
||||
*
|
||||
* Author: Sarah Sharp
|
||||
* Some code borrowed from the Linux EHCI driver.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
/* Up to 16 ms to halt an HC */
|
||||
#define XHCI_MAX_HALT_USEC (16*1000)
|
||||
/* HC not running - set to 1 when run/stop bit is cleared. */
|
||||
#define XHCI_STS_HALT (1<<0)
|
||||
|
||||
/* HCCPARAMS offset from PCI base address */
|
||||
#define XHCI_HCC_PARAMS_OFFSET 0x10
|
||||
/* HCCPARAMS contains the first extended capability pointer */
|
||||
#define XHCI_HCC_EXT_CAPS(p) (((p)>>16)&0xffff)
|
||||
|
||||
/* Command and Status registers offset from the Operational Registers address */
|
||||
#define XHCI_CMD_OFFSET 0x00
|
||||
#define XHCI_STS_OFFSET 0x04
|
||||
|
||||
#define XHCI_MAX_EXT_CAPS 50
|
||||
|
||||
/* Capability Register */
|
||||
/* bits 7:0 - how long is the Capabilities register */
|
||||
#define XHCI_HC_LENGTH(p) (((p)>>00)&0x00ff)
|
||||
|
||||
/* Extended capability register fields */
|
||||
#define XHCI_EXT_CAPS_ID(p) (((p)>>0)&0xff)
|
||||
#define XHCI_EXT_CAPS_NEXT(p) (((p)>>8)&0xff)
|
||||
#define XHCI_EXT_CAPS_VAL(p) ((p)>>16)
|
||||
/* Extended capability IDs - ID 0 reserved */
|
||||
#define XHCI_EXT_CAPS_LEGACY 1
|
||||
#define XHCI_EXT_CAPS_PROTOCOL 2
|
||||
#define XHCI_EXT_CAPS_PM 3
|
||||
#define XHCI_EXT_CAPS_VIRT 4
|
||||
#define XHCI_EXT_CAPS_ROUTE 5
|
||||
/* IDs 6-9 reserved */
|
||||
#define XHCI_EXT_CAPS_DEBUG 10
|
||||
/* USB Legacy Support Capability - section 7.1.1 */
|
||||
#define XHCI_HC_BIOS_OWNED (1 << 16)
|
||||
#define XHCI_HC_OS_OWNED (1 << 24)
|
||||
|
||||
/* USB Legacy Support Capability - section 7.1.1 */
|
||||
/* Add this offset, plus the value of xECP in HCCPARAMS to the base address */
|
||||
#define XHCI_LEGACY_SUPPORT_OFFSET (0x00)
|
||||
|
||||
/* USB Legacy Support Control and Status Register - section 7.1.2 */
|
||||
/* Add this offset, plus the value of xECP in HCCPARAMS to the base address */
|
||||
#define XHCI_LEGACY_CONTROL_OFFSET (0x04)
|
||||
/* bits 1:3, 5:12, and 17:19 need to be preserved; bits 21:28 should be zero */
|
||||
#define XHCI_LEGACY_DISABLE_SMI ((0x7 << 1) + (0xff << 5) + (0x7 << 17))
|
||||
#define XHCI_LEGACY_SMI_EVENTS (0x7 << 29)
|
||||
|
||||
/* USB 2.0 xHCI 0.96 L1C capability - section 7.2.2.1.3.2 */
|
||||
#define XHCI_L1C (1 << 16)
|
||||
|
||||
/* USB 2.0 xHCI 1.0 hardware LMP capability - section 7.2.2.1.3.2 */
|
||||
#define XHCI_HLC (1 << 19)
|
||||
|
||||
/* command register values to disable interrupts and halt the HC */
|
||||
/* start/stop HC execution - do not write unless HC is halted*/
|
||||
#define XHCI_CMD_RUN (1 << 0)
|
||||
/* Event Interrupt Enable - get irq when EINT bit is set in USBSTS register */
|
||||
#define XHCI_CMD_EIE (1 << 2)
|
||||
/* Host System Error Interrupt Enable - get irq when HSEIE bit set in USBSTS */
|
||||
#define XHCI_CMD_HSEIE (1 << 3)
|
||||
/* Enable Wrap Event - '1' means xHC generates an event when MFINDEX wraps. */
|
||||
#define XHCI_CMD_EWE (1 << 10)
|
||||
|
||||
#define XHCI_IRQS (XHCI_CMD_EIE | XHCI_CMD_HSEIE | XHCI_CMD_EWE)
|
||||
|
||||
/* true: Controller Not Ready to accept doorbell or op reg writes after reset */
|
||||
#define XHCI_STS_CNR (1 << 11)
|
||||
|
||||
#include <linux/io.h>
|
||||
|
||||
/**
|
||||
* Return the next extended capability pointer register.
|
||||
*
|
||||
* @base PCI register base address.
|
||||
*
|
||||
* @ext_offset Offset of the 32-bit register that contains the extended
|
||||
* capabilites pointer. If searching for the first extended capability, pass
|
||||
* in XHCI_HCC_PARAMS_OFFSET. If searching for the next extended capability,
|
||||
* pass in the offset of the current extended capability register.
|
||||
*
|
||||
* Returns 0 if there is no next extended capability register or returns the register offset
|
||||
* from the PCI registers base address.
|
||||
*/
|
||||
static inline int xhci_find_next_cap_offset(void __iomem *base, int ext_offset)
|
||||
{
|
||||
u32 next;
|
||||
|
||||
next = readl(base + ext_offset);
|
||||
|
||||
if (ext_offset == XHCI_HCC_PARAMS_OFFSET) {
|
||||
/* Find the first extended capability */
|
||||
next = XHCI_HCC_EXT_CAPS(next);
|
||||
ext_offset = 0;
|
||||
} else {
|
||||
/* Find the next extended capability */
|
||||
next = XHCI_EXT_CAPS_NEXT(next);
|
||||
}
|
||||
|
||||
if (!next)
|
||||
return 0;
|
||||
/*
|
||||
* Address calculation from offset of extended capabilities
|
||||
* (or HCCPARAMS) register - see section 5.3.6 and section 7.
|
||||
*/
|
||||
return ext_offset + (next << 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the offset of the extended capabilities with capability ID id.
|
||||
*
|
||||
* @base PCI MMIO registers base address.
|
||||
* @ext_offset Offset from base of the first extended capability to look at,
|
||||
* or the address of HCCPARAMS.
|
||||
* @id Extended capability ID to search for.
|
||||
*
|
||||
* This uses an arbitrary limit of XHCI_MAX_EXT_CAPS extended capabilities
|
||||
* to make sure that the list doesn't contain a loop.
|
||||
*/
|
||||
static inline int xhci_find_ext_cap_by_id(void __iomem *base, int ext_offset, int id)
|
||||
{
|
||||
u32 val;
|
||||
int limit = XHCI_MAX_EXT_CAPS;
|
||||
|
||||
while (ext_offset && limit > 0) {
|
||||
val = readl(base + ext_offset);
|
||||
if (XHCI_EXT_CAPS_ID(val) == id)
|
||||
break;
|
||||
ext_offset = xhci_find_next_cap_offset(base, ext_offset);
|
||||
limit--;
|
||||
}
|
||||
if (limit > 0)
|
||||
return ext_offset;
|
||||
return 0;
|
||||
}
|
||||
3
addons/ehci-pci/src/4.4.180/Makefile
Normal file
3
addons/ehci-pci/src/4.4.180/Makefile
Normal file
@@ -0,0 +1,3 @@
|
||||
obj-y += pci-quirks.o
|
||||
obj-m += ehci-hcd.o
|
||||
obj-m += ehci-pci.o
|
||||
1085
addons/ehci-pci/src/4.4.180/ehci-dbg.c
Normal file
1085
addons/ehci-pci/src/4.4.180/ehci-dbg.c
Normal file
File diff suppressed because it is too large
Load Diff
1396
addons/ehci-pci/src/4.4.180/ehci-hcd.c
Normal file
1396
addons/ehci-pci/src/4.4.180/ehci-hcd.c
Normal file
File diff suppressed because it is too large
Load Diff
1329
addons/ehci-pci/src/4.4.180/ehci-hub.c
Normal file
1329
addons/ehci-pci/src/4.4.180/ehci-hub.c
Normal file
File diff suppressed because it is too large
Load Diff
246
addons/ehci-pci/src/4.4.180/ehci-mem.c
Normal file
246
addons/ehci-pci/src/4.4.180/ehci-mem.c
Normal file
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
* Copyright (c) 2001 by David Brownell
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/* this file is part of ehci-hcd.c */
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* There's basically three types of memory:
|
||||
* - data used only by the HCD ... kmalloc is fine
|
||||
* - async and periodic schedules, shared by HC and HCD ... these
|
||||
* need to use dma_pool or dma_alloc_coherent
|
||||
* - driver buffers, read/written by HC ... single shot DMA mapped
|
||||
*
|
||||
* There's also "register" data (e.g. PCI or SOC), which is memory mapped.
|
||||
* No memory seen by this driver is pageable.
|
||||
*/
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* Allocate the key transfer structures from the previously allocated pool */
|
||||
|
||||
static inline void ehci_qtd_init(struct ehci_hcd *ehci, struct ehci_qtd *qtd,
|
||||
dma_addr_t dma)
|
||||
{
|
||||
memset (qtd, 0, sizeof *qtd);
|
||||
qtd->qtd_dma = dma;
|
||||
qtd->hw_token = cpu_to_hc32(ehci, QTD_STS_HALT);
|
||||
qtd->hw_next = EHCI_LIST_END(ehci);
|
||||
qtd->hw_alt_next = EHCI_LIST_END(ehci);
|
||||
INIT_LIST_HEAD (&qtd->qtd_list);
|
||||
}
|
||||
|
||||
static struct ehci_qtd *ehci_qtd_alloc (struct ehci_hcd *ehci, gfp_t flags)
|
||||
{
|
||||
struct ehci_qtd *qtd;
|
||||
dma_addr_t dma;
|
||||
|
||||
qtd = dma_pool_alloc (ehci->qtd_pool, flags, &dma);
|
||||
if (qtd != NULL) {
|
||||
ehci_qtd_init(ehci, qtd, dma);
|
||||
}
|
||||
return qtd;
|
||||
}
|
||||
|
||||
static inline void ehci_qtd_free (struct ehci_hcd *ehci, struct ehci_qtd *qtd)
|
||||
{
|
||||
dma_pool_free (ehci->qtd_pool, qtd, qtd->qtd_dma);
|
||||
}
|
||||
|
||||
|
||||
static void qh_destroy(struct ehci_hcd *ehci, struct ehci_qh *qh)
|
||||
{
|
||||
/* clean qtds first, and know this is not linked */
|
||||
if (!list_empty (&qh->qtd_list) || qh->qh_next.ptr) {
|
||||
ehci_dbg (ehci, "unused qh not empty!\n");
|
||||
BUG ();
|
||||
}
|
||||
if (qh->dummy)
|
||||
ehci_qtd_free (ehci, qh->dummy);
|
||||
dma_pool_free(ehci->qh_pool, qh->hw, qh->qh_dma);
|
||||
kfree(qh);
|
||||
}
|
||||
|
||||
static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, gfp_t flags)
|
||||
{
|
||||
struct ehci_qh *qh;
|
||||
dma_addr_t dma;
|
||||
|
||||
qh = kzalloc(sizeof *qh, GFP_ATOMIC);
|
||||
if (!qh)
|
||||
goto done;
|
||||
qh->hw = (struct ehci_qh_hw *)
|
||||
dma_pool_alloc(ehci->qh_pool, flags, &dma);
|
||||
if (!qh->hw)
|
||||
goto fail;
|
||||
memset(qh->hw, 0, sizeof *qh->hw);
|
||||
qh->qh_dma = dma;
|
||||
// INIT_LIST_HEAD (&qh->qh_list);
|
||||
INIT_LIST_HEAD (&qh->qtd_list);
|
||||
INIT_LIST_HEAD(&qh->unlink_node);
|
||||
|
||||
/* dummy td enables safe urb queuing */
|
||||
qh->dummy = ehci_qtd_alloc (ehci, flags);
|
||||
if (qh->dummy == NULL) {
|
||||
ehci_dbg (ehci, "no dummy td\n");
|
||||
goto fail1;
|
||||
}
|
||||
done:
|
||||
return qh;
|
||||
fail1:
|
||||
dma_pool_free(ehci->qh_pool, qh->hw, qh->qh_dma);
|
||||
fail:
|
||||
kfree(qh);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* The queue heads and transfer descriptors are managed from pools tied
|
||||
* to each of the "per device" structures.
|
||||
* This is the initialisation and cleanup code.
|
||||
*/
|
||||
|
||||
static void ehci_mem_cleanup (struct ehci_hcd *ehci)
|
||||
{
|
||||
if (ehci->async)
|
||||
qh_destroy(ehci, ehci->async);
|
||||
ehci->async = NULL;
|
||||
|
||||
if (ehci->dummy)
|
||||
qh_destroy(ehci, ehci->dummy);
|
||||
ehci->dummy = NULL;
|
||||
|
||||
/* DMA consistent memory and pools */
|
||||
if (ehci->qtd_pool)
|
||||
dma_pool_destroy (ehci->qtd_pool);
|
||||
ehci->qtd_pool = NULL;
|
||||
|
||||
if (ehci->qh_pool) {
|
||||
dma_pool_destroy (ehci->qh_pool);
|
||||
ehci->qh_pool = NULL;
|
||||
}
|
||||
|
||||
if (ehci->itd_pool)
|
||||
dma_pool_destroy (ehci->itd_pool);
|
||||
ehci->itd_pool = NULL;
|
||||
|
||||
if (ehci->sitd_pool)
|
||||
dma_pool_destroy (ehci->sitd_pool);
|
||||
ehci->sitd_pool = NULL;
|
||||
|
||||
if (ehci->periodic)
|
||||
dma_free_coherent (ehci_to_hcd(ehci)->self.controller,
|
||||
ehci->periodic_size * sizeof (u32),
|
||||
ehci->periodic, ehci->periodic_dma);
|
||||
ehci->periodic = NULL;
|
||||
|
||||
/* shadow periodic table */
|
||||
kfree(ehci->pshadow);
|
||||
ehci->pshadow = NULL;
|
||||
}
|
||||
|
||||
/* remember to add cleanup code (above) if you add anything here */
|
||||
static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* QTDs for control/bulk/intr transfers */
|
||||
ehci->qtd_pool = dma_pool_create ("ehci_qtd",
|
||||
ehci_to_hcd(ehci)->self.controller,
|
||||
sizeof (struct ehci_qtd),
|
||||
32 /* byte alignment (for hw parts) */,
|
||||
4096 /* can't cross 4K */);
|
||||
if (!ehci->qtd_pool) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* QHs for control/bulk/intr transfers */
|
||||
ehci->qh_pool = dma_pool_create ("ehci_qh",
|
||||
ehci_to_hcd(ehci)->self.controller,
|
||||
sizeof(struct ehci_qh_hw),
|
||||
32 /* byte alignment (for hw parts) */,
|
||||
4096 /* can't cross 4K */);
|
||||
if (!ehci->qh_pool) {
|
||||
goto fail;
|
||||
}
|
||||
ehci->async = ehci_qh_alloc (ehci, flags);
|
||||
if (!ehci->async) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* ITD for high speed ISO transfers */
|
||||
ehci->itd_pool = dma_pool_create ("ehci_itd",
|
||||
ehci_to_hcd(ehci)->self.controller,
|
||||
sizeof (struct ehci_itd),
|
||||
32 /* byte alignment (for hw parts) */,
|
||||
4096 /* can't cross 4K */);
|
||||
if (!ehci->itd_pool) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* SITD for full/low speed split ISO transfers */
|
||||
ehci->sitd_pool = dma_pool_create ("ehci_sitd",
|
||||
ehci_to_hcd(ehci)->self.controller,
|
||||
sizeof (struct ehci_sitd),
|
||||
32 /* byte alignment (for hw parts) */,
|
||||
4096 /* can't cross 4K */);
|
||||
if (!ehci->sitd_pool) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Hardware periodic table */
|
||||
ehci->periodic = (__le32 *)
|
||||
dma_alloc_coherent (ehci_to_hcd(ehci)->self.controller,
|
||||
ehci->periodic_size * sizeof(__le32),
|
||||
&ehci->periodic_dma, flags);
|
||||
if (ehci->periodic == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (ehci->use_dummy_qh) {
|
||||
struct ehci_qh_hw *hw;
|
||||
ehci->dummy = ehci_qh_alloc(ehci, flags);
|
||||
if (!ehci->dummy)
|
||||
goto fail;
|
||||
|
||||
hw = ehci->dummy->hw;
|
||||
hw->hw_next = EHCI_LIST_END(ehci);
|
||||
hw->hw_qtd_next = EHCI_LIST_END(ehci);
|
||||
hw->hw_alt_next = EHCI_LIST_END(ehci);
|
||||
ehci->dummy->hw = hw;
|
||||
|
||||
for (i = 0; i < ehci->periodic_size; i++)
|
||||
ehci->periodic[i] = cpu_to_hc32(ehci,
|
||||
ehci->dummy->qh_dma);
|
||||
} else {
|
||||
for (i = 0; i < ehci->periodic_size; i++)
|
||||
ehci->periodic[i] = EHCI_LIST_END(ehci);
|
||||
}
|
||||
|
||||
/* software shadow of hardware table */
|
||||
ehci->pshadow = kcalloc(ehci->periodic_size, sizeof(void *), flags);
|
||||
if (ehci->pshadow != NULL)
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
ehci_dbg (ehci, "couldn't init memory\n");
|
||||
ehci_mem_cleanup (ehci);
|
||||
return -ENOMEM;
|
||||
}
|
||||
435
addons/ehci-pci/src/4.4.180/ehci-pci.c
Normal file
435
addons/ehci-pci/src/4.4.180/ehci-pci.c
Normal file
@@ -0,0 +1,435 @@
|
||||
/*
|
||||
* EHCI HCD (Host Controller Driver) PCI Bus Glue.
|
||||
*
|
||||
* Copyright (c) 2000-2004 by David Brownell
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb/hcd.h>
|
||||
|
||||
#include "ehci.h"
|
||||
#include "pci-quirks.h"
|
||||
|
||||
#define DRIVER_DESC "EHCI PCI platform driver"
|
||||
|
||||
static const char hcd_name[] = "ehci-pci";
|
||||
|
||||
/* defined here to avoid adding to pci_ids.h for single instance use */
|
||||
#define PCI_DEVICE_ID_INTEL_CE4100_USB 0x2e70
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
#define PCI_DEVICE_ID_INTEL_QUARK_X1000_SOC 0x0939
|
||||
static inline bool is_intel_quark_x1000(struct pci_dev *pdev)
|
||||
{
|
||||
return pdev->vendor == PCI_VENDOR_ID_INTEL &&
|
||||
pdev->device == PCI_DEVICE_ID_INTEL_QUARK_X1000_SOC;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the list of PCI IDs for the devices that have EHCI USB class and
|
||||
* specific drivers for that. One of the example is a ChipIdea device installed
|
||||
* on some Intel MID platforms.
|
||||
*/
|
||||
static const struct pci_device_id bypass_pci_id_table[] = {
|
||||
/* ChipIdea on Intel MID platform */
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0811), },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0829), },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe006), },
|
||||
{}
|
||||
};
|
||||
|
||||
static inline bool is_bypassed_id(struct pci_dev *pdev)
|
||||
{
|
||||
return !!pci_match_id(bypass_pci_id_table, pdev);
|
||||
}
|
||||
|
||||
/*
|
||||
* 0x84 is the offset of in/out threshold register,
|
||||
* and it is the same offset as the register of 'hostpc'.
|
||||
*/
|
||||
#define intel_quark_x1000_insnreg01 hostpc
|
||||
|
||||
/* Maximum usable threshold value is 0x7f dwords for both IN and OUT */
|
||||
#define INTEL_QUARK_X1000_EHCI_MAX_THRESHOLD 0x007f007f
|
||||
|
||||
/* called after powerup, by probe or system-pm "wakeup" */
|
||||
static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev)
|
||||
{
|
||||
int retval;
|
||||
|
||||
/* we expect static quirk code to handle the "extended capabilities"
|
||||
* (currently just BIOS handoff) allowed starting with EHCI 0.96
|
||||
*/
|
||||
|
||||
/* PCI Memory-Write-Invalidate cycle support is optional (uncommon) */
|
||||
retval = pci_set_mwi(pdev);
|
||||
if (!retval)
|
||||
ehci_dbg(ehci, "MWI active\n");
|
||||
|
||||
/* Reset the threshold limit */
|
||||
if (is_intel_quark_x1000(pdev)) {
|
||||
/*
|
||||
* For the Intel QUARK X1000, raise the I/O threshold to the
|
||||
* maximum usable value in order to improve performance.
|
||||
*/
|
||||
ehci_writel(ehci, INTEL_QUARK_X1000_EHCI_MAX_THRESHOLD,
|
||||
ehci->regs->intel_quark_x1000_insnreg01);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* called during probe() after chip reset completes */
|
||||
static int ehci_pci_setup(struct usb_hcd *hcd)
|
||||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
|
||||
u32 temp;
|
||||
int retval;
|
||||
|
||||
ehci->caps = hcd->regs;
|
||||
|
||||
/*
|
||||
* ehci_init() causes memory for DMA transfers to be
|
||||
* allocated. Thus, any vendor-specific workarounds based on
|
||||
* limiting the type of memory used for DMA transfers must
|
||||
* happen before ehci_setup() is called.
|
||||
*
|
||||
* Most other workarounds can be done either before or after
|
||||
* init and reset; they are located here too.
|
||||
*/
|
||||
switch (pdev->vendor) {
|
||||
case PCI_VENDOR_ID_TOSHIBA_2:
|
||||
/* celleb's companion chip */
|
||||
if (pdev->device == 0x01b5) {
|
||||
#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
|
||||
ehci->big_endian_mmio = 1;
|
||||
#else
|
||||
ehci_warn(ehci,
|
||||
"unsupported big endian Toshiba quirk\n");
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case PCI_VENDOR_ID_NVIDIA:
|
||||
/* NVidia reports that certain chips don't handle
|
||||
* QH, ITD, or SITD addresses above 2GB. (But TD,
|
||||
* data buffer, and periodic schedule are normal.)
|
||||
*/
|
||||
switch (pdev->device) {
|
||||
case 0x003c: /* MCP04 */
|
||||
case 0x005b: /* CK804 */
|
||||
case 0x00d8: /* CK8 */
|
||||
case 0x00e8: /* CK8S */
|
||||
if (pci_set_consistent_dma_mask(pdev,
|
||||
DMA_BIT_MASK(31)) < 0)
|
||||
ehci_warn(ehci, "can't enable NVidia "
|
||||
"workaround for >2GB RAM\n");
|
||||
break;
|
||||
|
||||
/* Some NForce2 chips have problems with selective suspend;
|
||||
* fixed in newer silicon.
|
||||
*/
|
||||
case 0x0068:
|
||||
if (pdev->revision < 0xa4)
|
||||
ehci->no_selective_suspend = 1;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case PCI_VENDOR_ID_INTEL:
|
||||
if (pdev->device == PCI_DEVICE_ID_INTEL_CE4100_USB)
|
||||
hcd->has_tt = 1;
|
||||
break;
|
||||
case PCI_VENDOR_ID_TDI:
|
||||
if (pdev->device == PCI_DEVICE_ID_TDI_EHCI)
|
||||
hcd->has_tt = 1;
|
||||
break;
|
||||
case PCI_VENDOR_ID_AMD:
|
||||
/* AMD PLL quirk */
|
||||
if (usb_amd_find_chipset_info())
|
||||
ehci->amd_pll_fix = 1;
|
||||
/* AMD8111 EHCI doesn't work, according to AMD errata */
|
||||
if (pdev->device == 0x7463) {
|
||||
ehci_info(ehci, "ignoring AMD8111 (errata)\n");
|
||||
retval = -EIO;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* EHCI controller on AMD SB700/SB800/Hudson-2/3 platforms may
|
||||
* read/write memory space which does not belong to it when
|
||||
* there is NULL pointer with T-bit set to 1 in the frame list
|
||||
* table. To avoid the issue, the frame list link pointer
|
||||
* should always contain a valid pointer to a inactive qh.
|
||||
*/
|
||||
if (pdev->device == 0x7808) {
|
||||
ehci->use_dummy_qh = 1;
|
||||
ehci_info(ehci, "applying AMD SB700/SB800/Hudson-2/3 EHCI dummy qh workaround\n");
|
||||
}
|
||||
break;
|
||||
case PCI_VENDOR_ID_VIA:
|
||||
if (pdev->device == 0x3104 && (pdev->revision & 0xf0) == 0x60) {
|
||||
u8 tmp;
|
||||
|
||||
/* The VT6212 defaults to a 1 usec EHCI sleep time which
|
||||
* hogs the PCI bus *badly*. Setting bit 5 of 0x4B makes
|
||||
* that sleep time use the conventional 10 usec.
|
||||
*/
|
||||
pci_read_config_byte(pdev, 0x4b, &tmp);
|
||||
if (tmp & 0x20)
|
||||
break;
|
||||
pci_write_config_byte(pdev, 0x4b, tmp | 0x20);
|
||||
}
|
||||
break;
|
||||
case PCI_VENDOR_ID_ATI:
|
||||
/* AMD PLL quirk */
|
||||
if (usb_amd_find_chipset_info())
|
||||
ehci->amd_pll_fix = 1;
|
||||
|
||||
/*
|
||||
* EHCI controller on AMD SB700/SB800/Hudson-2/3 platforms may
|
||||
* read/write memory space which does not belong to it when
|
||||
* there is NULL pointer with T-bit set to 1 in the frame list
|
||||
* table. To avoid the issue, the frame list link pointer
|
||||
* should always contain a valid pointer to a inactive qh.
|
||||
*/
|
||||
if (pdev->device == 0x4396) {
|
||||
ehci->use_dummy_qh = 1;
|
||||
ehci_info(ehci, "applying AMD SB700/SB800/Hudson-2/3 EHCI dummy qh workaround\n");
|
||||
}
|
||||
/* SB600 and old version of SB700 have a bug in EHCI controller,
|
||||
* which causes usb devices lose response in some cases.
|
||||
*/
|
||||
if ((pdev->device == 0x4386 || pdev->device == 0x4396) &&
|
||||
usb_amd_hang_symptom_quirk()) {
|
||||
u8 tmp;
|
||||
ehci_info(ehci, "applying AMD SB600/SB700 USB freeze workaround\n");
|
||||
pci_read_config_byte(pdev, 0x53, &tmp);
|
||||
pci_write_config_byte(pdev, 0x53, tmp | (1<<3));
|
||||
}
|
||||
break;
|
||||
case PCI_VENDOR_ID_NETMOS:
|
||||
/* MosChip frame-index-register bug */
|
||||
ehci_info(ehci, "applying MosChip frame-index workaround\n");
|
||||
ehci->frame_index_bug = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* optional debug port, normally in the first BAR */
|
||||
temp = pci_find_capability(pdev, PCI_CAP_ID_DBG);
|
||||
if (temp) {
|
||||
pci_read_config_dword(pdev, temp, &temp);
|
||||
temp >>= 16;
|
||||
if (((temp >> 13) & 7) == 1) {
|
||||
u32 hcs_params = ehci_readl(ehci,
|
||||
&ehci->caps->hcs_params);
|
||||
|
||||
temp &= 0x1fff;
|
||||
ehci->debug = hcd->regs + temp;
|
||||
temp = ehci_readl(ehci, &ehci->debug->control);
|
||||
ehci_info(ehci, "debug port %d%s\n",
|
||||
HCS_DEBUG_PORT(hcs_params),
|
||||
(temp & DBGP_ENABLED) ? " IN USE" : "");
|
||||
if (!(temp & DBGP_ENABLED))
|
||||
ehci->debug = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
retval = ehci_setup(hcd);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
/* These workarounds need to be applied after ehci_setup() */
|
||||
switch (pdev->vendor) {
|
||||
case PCI_VENDOR_ID_NEC:
|
||||
ehci->need_io_watchdog = 0;
|
||||
break;
|
||||
case PCI_VENDOR_ID_INTEL:
|
||||
ehci->need_io_watchdog = 0;
|
||||
break;
|
||||
case PCI_VENDOR_ID_NVIDIA:
|
||||
switch (pdev->device) {
|
||||
/* MCP89 chips on the MacBookAir3,1 give EPROTO when
|
||||
* fetching device descriptors unless LPM is disabled.
|
||||
* There are also intermittent problems enumerating
|
||||
* devices with PPCD enabled.
|
||||
*/
|
||||
case 0x0d9d:
|
||||
ehci_info(ehci, "disable ppcd for nvidia mcp89\n");
|
||||
ehci->has_ppcd = 0;
|
||||
ehci->command &= ~CMD_PPCEE;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* at least the Genesys GL880S needs fixup here */
|
||||
temp = HCS_N_CC(ehci->hcs_params) * HCS_N_PCC(ehci->hcs_params);
|
||||
temp &= 0x0f;
|
||||
if (temp && HCS_N_PORTS(ehci->hcs_params) > temp) {
|
||||
ehci_dbg(ehci, "bogus port configuration: "
|
||||
"cc=%d x pcc=%d < ports=%d\n",
|
||||
HCS_N_CC(ehci->hcs_params),
|
||||
HCS_N_PCC(ehci->hcs_params),
|
||||
HCS_N_PORTS(ehci->hcs_params));
|
||||
|
||||
switch (pdev->vendor) {
|
||||
case 0x17a0: /* GENESYS */
|
||||
/* GL880S: should be PORTS=2 */
|
||||
temp |= (ehci->hcs_params & ~0xf);
|
||||
ehci->hcs_params = temp;
|
||||
break;
|
||||
case PCI_VENDOR_ID_NVIDIA:
|
||||
/* NF4: should be PCC=10 */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Serial Bus Release Number is at PCI 0x60 offset */
|
||||
if (pdev->vendor == PCI_VENDOR_ID_STMICRO
|
||||
&& pdev->device == PCI_DEVICE_ID_STMICRO_USB_HOST)
|
||||
; /* ConneXT has no sbrn register */
|
||||
else
|
||||
pci_read_config_byte(pdev, 0x60, &ehci->sbrn);
|
||||
|
||||
/* Keep this around for a while just in case some EHCI
|
||||
* implementation uses legacy PCI PM support. This test
|
||||
* can be removed on 17 Dec 2009 if the dev_warn() hasn't
|
||||
* been triggered by then.
|
||||
*/
|
||||
if (!device_can_wakeup(&pdev->dev)) {
|
||||
u16 port_wake;
|
||||
|
||||
pci_read_config_word(pdev, 0x62, &port_wake);
|
||||
if (port_wake & 0x0001) {
|
||||
dev_warn(&pdev->dev, "Enabling legacy PCI PM\n");
|
||||
device_set_wakeup_capable(&pdev->dev, 1);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
if (ehci->no_selective_suspend && device_can_wakeup(&pdev->dev))
|
||||
ehci_warn(ehci, "selective suspend/wakeup unavailable\n");
|
||||
#endif
|
||||
|
||||
retval = ehci_pci_reinit(ehci, pdev);
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
/* suspend/resume, section 4.3 */
|
||||
|
||||
/* These routines rely on the PCI bus glue
|
||||
* to handle powerdown and wakeup, and currently also on
|
||||
* transceivers that don't need any software attention to set up
|
||||
* the right sort of wakeup.
|
||||
* Also they depend on separate root hub suspend/resume.
|
||||
*/
|
||||
|
||||
static int ehci_pci_resume(struct usb_hcd *hcd, bool hibernated)
|
||||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
|
||||
|
||||
if (ehci_resume(hcd, hibernated) != 0)
|
||||
(void) ehci_pci_reinit(ehci, pdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define ehci_suspend NULL
|
||||
#define ehci_pci_resume NULL
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static struct hc_driver __read_mostly ehci_pci_hc_driver;
|
||||
|
||||
static const struct ehci_driver_overrides pci_overrides __initconst = {
|
||||
.reset = ehci_pci_setup,
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static int ehci_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
{
|
||||
if (is_bypassed_id(pdev))
|
||||
return -ENODEV;
|
||||
return usb_hcd_pci_probe(pdev, id);
|
||||
}
|
||||
|
||||
/* PCI driver selection metadata; PCI hotplugging uses this */
|
||||
static const struct pci_device_id pci_ids [] = { {
|
||||
/* handle any USB 2.0 EHCI controller */
|
||||
PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_EHCI, ~0),
|
||||
.driver_data = (unsigned long) &ehci_pci_hc_driver,
|
||||
}, {
|
||||
PCI_VDEVICE(STMICRO, PCI_DEVICE_ID_STMICRO_USB_HOST),
|
||||
.driver_data = (unsigned long) &ehci_pci_hc_driver,
|
||||
},
|
||||
{ /* end: all zeroes */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, pci_ids);
|
||||
|
||||
/* pci driver glue; this is a "new style" PCI driver module */
|
||||
static struct pci_driver ehci_pci_driver = {
|
||||
.name = (char *) hcd_name,
|
||||
.id_table = pci_ids,
|
||||
|
||||
.probe = ehci_pci_probe,
|
||||
.remove = usb_hcd_pci_remove,
|
||||
.shutdown = usb_hcd_pci_shutdown,
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
.driver = {
|
||||
.pm = &usb_hcd_pci_pm_ops
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init ehci_pci_init(void)
|
||||
{
|
||||
if (usb_disabled())
|
||||
return -ENODEV;
|
||||
|
||||
pr_info("%s: " DRIVER_DESC "\n", hcd_name);
|
||||
|
||||
ehci_init_driver(&ehci_pci_hc_driver, &pci_overrides);
|
||||
|
||||
/* Entries for the PCI suspend/resume callbacks are special */
|
||||
ehci_pci_hc_driver.pci_suspend = ehci_suspend;
|
||||
ehci_pci_hc_driver.pci_resume = ehci_pci_resume;
|
||||
|
||||
return pci_register_driver(&ehci_pci_driver);
|
||||
}
|
||||
module_init(ehci_pci_init);
|
||||
|
||||
static void __exit ehci_pci_cleanup(void)
|
||||
{
|
||||
pci_unregister_driver(&ehci_pci_driver);
|
||||
}
|
||||
module_exit(ehci_pci_cleanup);
|
||||
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_AUTHOR("David Brownell");
|
||||
MODULE_AUTHOR("Alan Stern");
|
||||
MODULE_LICENSE("GPL");
|
||||
1476
addons/ehci-pci/src/4.4.180/ehci-q.c
Normal file
1476
addons/ehci-pci/src/4.4.180/ehci-q.c
Normal file
File diff suppressed because it is too large
Load Diff
2517
addons/ehci-pci/src/4.4.180/ehci-sched.c
Normal file
2517
addons/ehci-pci/src/4.4.180/ehci-sched.c
Normal file
File diff suppressed because it is too large
Load Diff
187
addons/ehci-pci/src/4.4.180/ehci-sysfs.c
Normal file
187
addons/ehci-pci/src/4.4.180/ehci-sysfs.c
Normal file
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* Copyright (C) 2007 by Alan Stern
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/* this file is part of ehci-hcd.c */
|
||||
|
||||
|
||||
/* Display the ports dedicated to the companion controller */
|
||||
static ssize_t show_companion(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct ehci_hcd *ehci;
|
||||
int nports, index, n;
|
||||
int count = PAGE_SIZE;
|
||||
char *ptr = buf;
|
||||
|
||||
ehci = hcd_to_ehci(dev_get_drvdata(dev));
|
||||
nports = HCS_N_PORTS(ehci->hcs_params);
|
||||
|
||||
for (index = 0; index < nports; ++index) {
|
||||
if (test_bit(index, &ehci->companion_ports)) {
|
||||
n = scnprintf(ptr, count, "%d\n", index + 1);
|
||||
ptr += n;
|
||||
count -= n;
|
||||
}
|
||||
}
|
||||
return ptr - buf;
|
||||
}
|
||||
|
||||
/*
|
||||
* Dedicate or undedicate a port to the companion controller.
|
||||
* Syntax is "[-]portnum", where a leading '-' sign means
|
||||
* return control of the port to the EHCI controller.
|
||||
*/
|
||||
static ssize_t store_companion(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct ehci_hcd *ehci;
|
||||
int portnum, new_owner;
|
||||
|
||||
ehci = hcd_to_ehci(dev_get_drvdata(dev));
|
||||
new_owner = PORT_OWNER; /* Owned by companion */
|
||||
if (sscanf(buf, "%d", &portnum) != 1)
|
||||
return -EINVAL;
|
||||
if (portnum < 0) {
|
||||
portnum = - portnum;
|
||||
new_owner = 0; /* Owned by EHCI */
|
||||
}
|
||||
if (portnum <= 0 || portnum > HCS_N_PORTS(ehci->hcs_params))
|
||||
return -ENOENT;
|
||||
portnum--;
|
||||
if (new_owner)
|
||||
set_bit(portnum, &ehci->companion_ports);
|
||||
else
|
||||
clear_bit(portnum, &ehci->companion_ports);
|
||||
set_owner(ehci, portnum, new_owner);
|
||||
return count;
|
||||
}
|
||||
static DEVICE_ATTR(companion, 0644, show_companion, store_companion);
|
||||
|
||||
|
||||
/*
|
||||
* Display / Set uframe_periodic_max
|
||||
*/
|
||||
static ssize_t show_uframe_periodic_max(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct ehci_hcd *ehci;
|
||||
int n;
|
||||
|
||||
ehci = hcd_to_ehci(dev_get_drvdata(dev));
|
||||
n = scnprintf(buf, PAGE_SIZE, "%d\n", ehci->uframe_periodic_max);
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
static ssize_t store_uframe_periodic_max(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct ehci_hcd *ehci;
|
||||
unsigned uframe_periodic_max;
|
||||
unsigned uframe;
|
||||
unsigned long flags;
|
||||
ssize_t ret;
|
||||
|
||||
ehci = hcd_to_ehci(dev_get_drvdata(dev));
|
||||
if (kstrtouint(buf, 0, &uframe_periodic_max) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (uframe_periodic_max < 100 || uframe_periodic_max >= 125) {
|
||||
ehci_info(ehci, "rejecting invalid request for "
|
||||
"uframe_periodic_max=%u\n", uframe_periodic_max);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = -EINVAL;
|
||||
|
||||
/*
|
||||
* lock, so that our checking does not race with possible periodic
|
||||
* bandwidth allocation through submitting new urbs.
|
||||
*/
|
||||
spin_lock_irqsave (&ehci->lock, flags);
|
||||
|
||||
/*
|
||||
* for request to decrease max periodic bandwidth, we have to check
|
||||
* to see whether the decrease is possible.
|
||||
*/
|
||||
if (uframe_periodic_max < ehci->uframe_periodic_max) {
|
||||
u8 allocated_max = 0;
|
||||
|
||||
for (uframe = 0; uframe < EHCI_BANDWIDTH_SIZE; ++uframe)
|
||||
allocated_max = max(allocated_max,
|
||||
ehci->bandwidth[uframe]);
|
||||
|
||||
if (allocated_max > uframe_periodic_max) {
|
||||
ehci_info(ehci,
|
||||
"cannot decrease uframe_periodic_max because "
|
||||
"periodic bandwidth is already allocated "
|
||||
"(%u > %u)\n",
|
||||
allocated_max, uframe_periodic_max);
|
||||
goto out_unlock;
|
||||
}
|
||||
}
|
||||
|
||||
/* increasing is always ok */
|
||||
|
||||
ehci_info(ehci, "setting max periodic bandwidth to %u%% "
|
||||
"(== %u usec/uframe)\n",
|
||||
100*uframe_periodic_max/125, uframe_periodic_max);
|
||||
|
||||
if (uframe_periodic_max != 100)
|
||||
ehci_warn(ehci, "max periodic bandwidth set is non-standard\n");
|
||||
|
||||
ehci->uframe_periodic_max = uframe_periodic_max;
|
||||
ret = count;
|
||||
|
||||
out_unlock:
|
||||
spin_unlock_irqrestore (&ehci->lock, flags);
|
||||
return ret;
|
||||
}
|
||||
static DEVICE_ATTR(uframe_periodic_max, 0644, show_uframe_periodic_max, store_uframe_periodic_max);
|
||||
|
||||
|
||||
static inline int create_sysfs_files(struct ehci_hcd *ehci)
|
||||
{
|
||||
struct device *controller = ehci_to_hcd(ehci)->self.controller;
|
||||
int i = 0;
|
||||
|
||||
/* with integrated TT there is no companion! */
|
||||
if (!ehci_is_TDI(ehci))
|
||||
i = device_create_file(controller, &dev_attr_companion);
|
||||
if (i)
|
||||
goto out;
|
||||
|
||||
i = device_create_file(controller, &dev_attr_uframe_periodic_max);
|
||||
out:
|
||||
return i;
|
||||
}
|
||||
|
||||
static inline void remove_sysfs_files(struct ehci_hcd *ehci)
|
||||
{
|
||||
struct device *controller = ehci_to_hcd(ehci)->self.controller;
|
||||
|
||||
/* with integrated TT there is no companion! */
|
||||
if (!ehci_is_TDI(ehci))
|
||||
device_remove_file(controller, &dev_attr_companion);
|
||||
|
||||
device_remove_file(controller, &dev_attr_uframe_periodic_max);
|
||||
}
|
||||
433
addons/ehci-pci/src/4.4.180/ehci-timer.c
Normal file
433
addons/ehci-pci/src/4.4.180/ehci-timer.c
Normal file
@@ -0,0 +1,433 @@
|
||||
/*
|
||||
* Copyright (C) 2012 by Alan Stern
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
/* This file is part of ehci-hcd.c */
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* Set a bit in the USBCMD register */
|
||||
static void ehci_set_command_bit(struct ehci_hcd *ehci, u32 bit)
|
||||
{
|
||||
ehci->command |= bit;
|
||||
ehci_writel(ehci, ehci->command, &ehci->regs->command);
|
||||
|
||||
/* unblock posted write */
|
||||
ehci_readl(ehci, &ehci->regs->command);
|
||||
}
|
||||
|
||||
/* Clear a bit in the USBCMD register */
|
||||
static void ehci_clear_command_bit(struct ehci_hcd *ehci, u32 bit)
|
||||
{
|
||||
ehci->command &= ~bit;
|
||||
ehci_writel(ehci, ehci->command, &ehci->regs->command);
|
||||
|
||||
/* unblock posted write */
|
||||
ehci_readl(ehci, &ehci->regs->command);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* EHCI timer support... Now using hrtimers.
|
||||
*
|
||||
* Lots of different events are triggered from ehci->hrtimer. Whenever
|
||||
* the timer routine runs, it checks each possible event; events that are
|
||||
* currently enabled and whose expiration time has passed get handled.
|
||||
* The set of enabled events is stored as a collection of bitflags in
|
||||
* ehci->enabled_hrtimer_events, and they are numbered in order of
|
||||
* increasing delay values (ranging between 1 ms and 100 ms).
|
||||
*
|
||||
* Rather than implementing a sorted list or tree of all pending events,
|
||||
* we keep track only of the lowest-numbered pending event, in
|
||||
* ehci->next_hrtimer_event. Whenever ehci->hrtimer gets restarted, its
|
||||
* expiration time is set to the timeout value for this event.
|
||||
*
|
||||
* As a result, events might not get handled right away; the actual delay
|
||||
* could be anywhere up to twice the requested delay. This doesn't
|
||||
* matter, because none of the events are especially time-critical. The
|
||||
* ones that matter most all have a delay of 1 ms, so they will be
|
||||
* handled after 2 ms at most, which is okay. In addition to this, we
|
||||
* allow for an expiration range of 1 ms.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Delay lengths for the hrtimer event types.
|
||||
* Keep this list sorted by delay length, in the same order as
|
||||
* the event types indexed by enum ehci_hrtimer_event in ehci.h.
|
||||
*/
|
||||
static unsigned event_delays_ns[] = {
|
||||
1 * NSEC_PER_MSEC, /* EHCI_HRTIMER_POLL_ASS */
|
||||
1 * NSEC_PER_MSEC, /* EHCI_HRTIMER_POLL_PSS */
|
||||
1 * NSEC_PER_MSEC, /* EHCI_HRTIMER_POLL_DEAD */
|
||||
1125 * NSEC_PER_USEC, /* EHCI_HRTIMER_UNLINK_INTR */
|
||||
2 * NSEC_PER_MSEC, /* EHCI_HRTIMER_FREE_ITDS */
|
||||
5 * NSEC_PER_MSEC, /* EHCI_HRTIMER_START_UNLINK_INTR */
|
||||
6 * NSEC_PER_MSEC, /* EHCI_HRTIMER_ASYNC_UNLINKS */
|
||||
10 * NSEC_PER_MSEC, /* EHCI_HRTIMER_IAA_WATCHDOG */
|
||||
10 * NSEC_PER_MSEC, /* EHCI_HRTIMER_DISABLE_PERIODIC */
|
||||
15 * NSEC_PER_MSEC, /* EHCI_HRTIMER_DISABLE_ASYNC */
|
||||
100 * NSEC_PER_MSEC, /* EHCI_HRTIMER_IO_WATCHDOG */
|
||||
};
|
||||
|
||||
/* Enable a pending hrtimer event */
|
||||
static void ehci_enable_event(struct ehci_hcd *ehci, unsigned event,
|
||||
bool resched)
|
||||
{
|
||||
ktime_t *timeout = &ehci->hr_timeouts[event];
|
||||
|
||||
if (resched)
|
||||
*timeout = ktime_add(ktime_get(),
|
||||
ktime_set(0, event_delays_ns[event]));
|
||||
ehci->enabled_hrtimer_events |= (1 << event);
|
||||
|
||||
/* Track only the lowest-numbered pending event */
|
||||
if (event < ehci->next_hrtimer_event) {
|
||||
ehci->next_hrtimer_event = event;
|
||||
hrtimer_start_range_ns(&ehci->hrtimer, *timeout,
|
||||
NSEC_PER_MSEC, HRTIMER_MODE_ABS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Poll the STS_ASS status bit; see when it agrees with CMD_ASE */
|
||||
static void ehci_poll_ASS(struct ehci_hcd *ehci)
|
||||
{
|
||||
unsigned actual, want;
|
||||
|
||||
/* Don't enable anything if the controller isn't running (e.g., died) */
|
||||
if (ehci->rh_state != EHCI_RH_RUNNING)
|
||||
return;
|
||||
|
||||
want = (ehci->command & CMD_ASE) ? STS_ASS : 0;
|
||||
actual = ehci_readl(ehci, &ehci->regs->status) & STS_ASS;
|
||||
|
||||
if (want != actual) {
|
||||
|
||||
/* Poll again later, but give up after about 2-4 ms */
|
||||
if (ehci->ASS_poll_count++ < 2) {
|
||||
ehci_enable_event(ehci, EHCI_HRTIMER_POLL_ASS, true);
|
||||
return;
|
||||
}
|
||||
ehci_dbg(ehci, "Waited too long for the async schedule status (%x/%x), giving up\n",
|
||||
want, actual);
|
||||
}
|
||||
ehci->ASS_poll_count = 0;
|
||||
|
||||
/* The status is up-to-date; restart or stop the schedule as needed */
|
||||
if (want == 0) { /* Stopped */
|
||||
if (ehci->async_count > 0)
|
||||
ehci_set_command_bit(ehci, CMD_ASE);
|
||||
|
||||
} else { /* Running */
|
||||
if (ehci->async_count == 0) {
|
||||
|
||||
/* Turn off the schedule after a while */
|
||||
ehci_enable_event(ehci, EHCI_HRTIMER_DISABLE_ASYNC,
|
||||
true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Turn off the async schedule after a brief delay */
|
||||
static void ehci_disable_ASE(struct ehci_hcd *ehci)
|
||||
{
|
||||
ehci_clear_command_bit(ehci, CMD_ASE);
|
||||
}
|
||||
|
||||
|
||||
/* Poll the STS_PSS status bit; see when it agrees with CMD_PSE */
|
||||
static void ehci_poll_PSS(struct ehci_hcd *ehci)
|
||||
{
|
||||
unsigned actual, want;
|
||||
|
||||
/* Don't do anything if the controller isn't running (e.g., died) */
|
||||
if (ehci->rh_state != EHCI_RH_RUNNING)
|
||||
return;
|
||||
|
||||
want = (ehci->command & CMD_PSE) ? STS_PSS : 0;
|
||||
actual = ehci_readl(ehci, &ehci->regs->status) & STS_PSS;
|
||||
|
||||
if (want != actual) {
|
||||
|
||||
/* Poll again later, but give up after about 2-4 ms */
|
||||
if (ehci->PSS_poll_count++ < 2) {
|
||||
ehci_enable_event(ehci, EHCI_HRTIMER_POLL_PSS, true);
|
||||
return;
|
||||
}
|
||||
ehci_dbg(ehci, "Waited too long for the periodic schedule status (%x/%x), giving up\n",
|
||||
want, actual);
|
||||
}
|
||||
ehci->PSS_poll_count = 0;
|
||||
|
||||
/* The status is up-to-date; restart or stop the schedule as needed */
|
||||
if (want == 0) { /* Stopped */
|
||||
if (ehci->periodic_count > 0)
|
||||
ehci_set_command_bit(ehci, CMD_PSE);
|
||||
|
||||
} else { /* Running */
|
||||
if (ehci->periodic_count == 0) {
|
||||
|
||||
/* Turn off the schedule after a while */
|
||||
ehci_enable_event(ehci, EHCI_HRTIMER_DISABLE_PERIODIC,
|
||||
true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Turn off the periodic schedule after a brief delay */
|
||||
static void ehci_disable_PSE(struct ehci_hcd *ehci)
|
||||
{
|
||||
ehci_clear_command_bit(ehci, CMD_PSE);
|
||||
}
|
||||
|
||||
|
||||
/* Poll the STS_HALT status bit; see when a dead controller stops */
|
||||
static void ehci_handle_controller_death(struct ehci_hcd *ehci)
|
||||
{
|
||||
if (!(ehci_readl(ehci, &ehci->regs->status) & STS_HALT)) {
|
||||
|
||||
/* Give up after a few milliseconds */
|
||||
if (ehci->died_poll_count++ < 5) {
|
||||
/* Try again later */
|
||||
ehci_enable_event(ehci, EHCI_HRTIMER_POLL_DEAD, true);
|
||||
return;
|
||||
}
|
||||
ehci_warn(ehci, "Waited too long for the controller to stop, giving up\n");
|
||||
}
|
||||
|
||||
/* Clean up the mess */
|
||||
ehci->rh_state = EHCI_RH_HALTED;
|
||||
ehci_writel(ehci, 0, &ehci->regs->configured_flag);
|
||||
ehci_writel(ehci, 0, &ehci->regs->intr_enable);
|
||||
ehci_work(ehci);
|
||||
end_unlink_async(ehci);
|
||||
|
||||
/* Not in process context, so don't try to reset the controller */
|
||||
}
|
||||
|
||||
/* start to unlink interrupt QHs */
|
||||
static void ehci_handle_start_intr_unlinks(struct ehci_hcd *ehci)
|
||||
{
|
||||
bool stopped = (ehci->rh_state < EHCI_RH_RUNNING);
|
||||
|
||||
/*
|
||||
* Process all the QHs on the intr_unlink list that were added
|
||||
* before the current unlink cycle began. The list is in
|
||||
* temporal order, so stop when we reach the first entry in the
|
||||
* current cycle. But if the root hub isn't running then
|
||||
* process all the QHs on the list.
|
||||
*/
|
||||
while (!list_empty(&ehci->intr_unlink_wait)) {
|
||||
struct ehci_qh *qh;
|
||||
|
||||
qh = list_first_entry(&ehci->intr_unlink_wait,
|
||||
struct ehci_qh, unlink_node);
|
||||
if (!stopped && (qh->unlink_cycle ==
|
||||
ehci->intr_unlink_wait_cycle))
|
||||
break;
|
||||
list_del_init(&qh->unlink_node);
|
||||
start_unlink_intr(ehci, qh);
|
||||
}
|
||||
|
||||
/* Handle remaining entries later */
|
||||
if (!list_empty(&ehci->intr_unlink_wait)) {
|
||||
ehci_enable_event(ehci, EHCI_HRTIMER_START_UNLINK_INTR, true);
|
||||
++ehci->intr_unlink_wait_cycle;
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle unlinked interrupt QHs once they are gone from the hardware */
|
||||
static void ehci_handle_intr_unlinks(struct ehci_hcd *ehci)
|
||||
{
|
||||
bool stopped = (ehci->rh_state < EHCI_RH_RUNNING);
|
||||
|
||||
/*
|
||||
* Process all the QHs on the intr_unlink list that were added
|
||||
* before the current unlink cycle began. The list is in
|
||||
* temporal order, so stop when we reach the first entry in the
|
||||
* current cycle. But if the root hub isn't running then
|
||||
* process all the QHs on the list.
|
||||
*/
|
||||
ehci->intr_unlinking = true;
|
||||
while (!list_empty(&ehci->intr_unlink)) {
|
||||
struct ehci_qh *qh;
|
||||
|
||||
qh = list_first_entry(&ehci->intr_unlink, struct ehci_qh,
|
||||
unlink_node);
|
||||
if (!stopped && qh->unlink_cycle == ehci->intr_unlink_cycle)
|
||||
break;
|
||||
list_del_init(&qh->unlink_node);
|
||||
end_unlink_intr(ehci, qh);
|
||||
}
|
||||
|
||||
/* Handle remaining entries later */
|
||||
if (!list_empty(&ehci->intr_unlink)) {
|
||||
ehci_enable_event(ehci, EHCI_HRTIMER_UNLINK_INTR, true);
|
||||
++ehci->intr_unlink_cycle;
|
||||
}
|
||||
ehci->intr_unlinking = false;
|
||||
}
|
||||
|
||||
|
||||
/* Start another free-iTDs/siTDs cycle */
|
||||
static void start_free_itds(struct ehci_hcd *ehci)
|
||||
{
|
||||
if (!(ehci->enabled_hrtimer_events & BIT(EHCI_HRTIMER_FREE_ITDS))) {
|
||||
ehci->last_itd_to_free = list_entry(
|
||||
ehci->cached_itd_list.prev,
|
||||
struct ehci_itd, itd_list);
|
||||
ehci->last_sitd_to_free = list_entry(
|
||||
ehci->cached_sitd_list.prev,
|
||||
struct ehci_sitd, sitd_list);
|
||||
ehci_enable_event(ehci, EHCI_HRTIMER_FREE_ITDS, true);
|
||||
}
|
||||
}
|
||||
|
||||
/* Wait for controller to stop using old iTDs and siTDs */
|
||||
static void end_free_itds(struct ehci_hcd *ehci)
|
||||
{
|
||||
struct ehci_itd *itd, *n;
|
||||
struct ehci_sitd *sitd, *sn;
|
||||
|
||||
if (ehci->rh_state < EHCI_RH_RUNNING) {
|
||||
ehci->last_itd_to_free = NULL;
|
||||
ehci->last_sitd_to_free = NULL;
|
||||
}
|
||||
|
||||
list_for_each_entry_safe(itd, n, &ehci->cached_itd_list, itd_list) {
|
||||
list_del(&itd->itd_list);
|
||||
dma_pool_free(ehci->itd_pool, itd, itd->itd_dma);
|
||||
if (itd == ehci->last_itd_to_free)
|
||||
break;
|
||||
}
|
||||
list_for_each_entry_safe(sitd, sn, &ehci->cached_sitd_list, sitd_list) {
|
||||
list_del(&sitd->sitd_list);
|
||||
dma_pool_free(ehci->sitd_pool, sitd, sitd->sitd_dma);
|
||||
if (sitd == ehci->last_sitd_to_free)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!list_empty(&ehci->cached_itd_list) ||
|
||||
!list_empty(&ehci->cached_sitd_list))
|
||||
start_free_itds(ehci);
|
||||
}
|
||||
|
||||
|
||||
/* Handle lost (or very late) IAA interrupts */
|
||||
static void ehci_iaa_watchdog(struct ehci_hcd *ehci)
|
||||
{
|
||||
u32 cmd, status;
|
||||
|
||||
/*
|
||||
* Lost IAA irqs wedge things badly; seen first with a vt8235.
|
||||
* So we need this watchdog, but must protect it against both
|
||||
* (a) SMP races against real IAA firing and retriggering, and
|
||||
* (b) clean HC shutdown, when IAA watchdog was pending.
|
||||
*/
|
||||
if (!ehci->iaa_in_progress || ehci->rh_state != EHCI_RH_RUNNING)
|
||||
return;
|
||||
|
||||
/* If we get here, IAA is *REALLY* late. It's barely
|
||||
* conceivable that the system is so busy that CMD_IAAD
|
||||
* is still legitimately set, so let's be sure it's
|
||||
* clear before we read STS_IAA. (The HC should clear
|
||||
* CMD_IAAD when it sets STS_IAA.)
|
||||
*/
|
||||
cmd = ehci_readl(ehci, &ehci->regs->command);
|
||||
|
||||
/*
|
||||
* If IAA is set here it either legitimately triggered
|
||||
* after the watchdog timer expired (_way_ late, so we'll
|
||||
* still count it as lost) ... or a silicon erratum:
|
||||
* - VIA seems to set IAA without triggering the IRQ;
|
||||
* - IAAD potentially cleared without setting IAA.
|
||||
*/
|
||||
status = ehci_readl(ehci, &ehci->regs->status);
|
||||
if ((status & STS_IAA) || !(cmd & CMD_IAAD)) {
|
||||
COUNT(ehci->stats.lost_iaa);
|
||||
ehci_writel(ehci, STS_IAA, &ehci->regs->status);
|
||||
}
|
||||
|
||||
ehci_dbg(ehci, "IAA watchdog: status %x cmd %x\n", status, cmd);
|
||||
end_unlink_async(ehci);
|
||||
}
|
||||
|
||||
|
||||
/* Enable the I/O watchdog, if appropriate */
|
||||
static void turn_on_io_watchdog(struct ehci_hcd *ehci)
|
||||
{
|
||||
/* Not needed if the controller isn't running or it's already enabled */
|
||||
if (ehci->rh_state != EHCI_RH_RUNNING ||
|
||||
(ehci->enabled_hrtimer_events &
|
||||
BIT(EHCI_HRTIMER_IO_WATCHDOG)))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Isochronous transfers always need the watchdog.
|
||||
* For other sorts we use it only if the flag is set.
|
||||
*/
|
||||
if (ehci->isoc_count > 0 || (ehci->need_io_watchdog &&
|
||||
ehci->async_count + ehci->intr_count > 0))
|
||||
ehci_enable_event(ehci, EHCI_HRTIMER_IO_WATCHDOG, true);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Handler functions for the hrtimer event types.
|
||||
* Keep this array in the same order as the event types indexed by
|
||||
* enum ehci_hrtimer_event in ehci.h.
|
||||
*/
|
||||
static void (*event_handlers[])(struct ehci_hcd *) = {
|
||||
ehci_poll_ASS, /* EHCI_HRTIMER_POLL_ASS */
|
||||
ehci_poll_PSS, /* EHCI_HRTIMER_POLL_PSS */
|
||||
ehci_handle_controller_death, /* EHCI_HRTIMER_POLL_DEAD */
|
||||
ehci_handle_intr_unlinks, /* EHCI_HRTIMER_UNLINK_INTR */
|
||||
end_free_itds, /* EHCI_HRTIMER_FREE_ITDS */
|
||||
ehci_handle_start_intr_unlinks, /* EHCI_HRTIMER_START_UNLINK_INTR */
|
||||
unlink_empty_async, /* EHCI_HRTIMER_ASYNC_UNLINKS */
|
||||
ehci_iaa_watchdog, /* EHCI_HRTIMER_IAA_WATCHDOG */
|
||||
ehci_disable_PSE, /* EHCI_HRTIMER_DISABLE_PERIODIC */
|
||||
ehci_disable_ASE, /* EHCI_HRTIMER_DISABLE_ASYNC */
|
||||
ehci_work, /* EHCI_HRTIMER_IO_WATCHDOG */
|
||||
};
|
||||
|
||||
static enum hrtimer_restart ehci_hrtimer_func(struct hrtimer *t)
|
||||
{
|
||||
struct ehci_hcd *ehci = container_of(t, struct ehci_hcd, hrtimer);
|
||||
ktime_t now;
|
||||
unsigned long events;
|
||||
unsigned long flags;
|
||||
unsigned e;
|
||||
|
||||
spin_lock_irqsave(&ehci->lock, flags);
|
||||
|
||||
events = ehci->enabled_hrtimer_events;
|
||||
ehci->enabled_hrtimer_events = 0;
|
||||
ehci->next_hrtimer_event = EHCI_HRTIMER_NO_EVENT;
|
||||
|
||||
/*
|
||||
* Check each pending event. If its time has expired, handle
|
||||
* the event; otherwise re-enable it.
|
||||
*/
|
||||
now = ktime_get();
|
||||
for_each_set_bit(e, &events, EHCI_HRTIMER_NUM_EVENTS) {
|
||||
if (now.tv64 >= ehci->hr_timeouts[e].tv64)
|
||||
event_handlers[e](ehci);
|
||||
else
|
||||
ehci_enable_event(ehci, e, false);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&ehci->lock, flags);
|
||||
return HRTIMER_NORESTART;
|
||||
}
|
||||
895
addons/ehci-pci/src/4.4.180/ehci.h
Normal file
895
addons/ehci-pci/src/4.4.180/ehci.h
Normal file
@@ -0,0 +1,895 @@
|
||||
/*
|
||||
* Copyright (c) 2001-2002 by David Brownell
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_EHCI_HCD_H
|
||||
#define __LINUX_EHCI_HCD_H
|
||||
|
||||
/* definitions used for the EHCI driver */
|
||||
|
||||
/*
|
||||
* __hc32 and __hc16 are "Host Controller" types, they may be equivalent to
|
||||
* __leXX (normally) or __beXX (given EHCI_BIG_ENDIAN_DESC), depending on
|
||||
* the host controller implementation.
|
||||
*
|
||||
* To facilitate the strongest possible byte-order checking from "sparse"
|
||||
* and so on, we use __leXX unless that's not practical.
|
||||
*/
|
||||
#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_DESC
|
||||
typedef __u32 __bitwise __hc32;
|
||||
typedef __u16 __bitwise __hc16;
|
||||
#else
|
||||
#define __hc32 __le32
|
||||
#define __hc16 __le16
|
||||
#endif
|
||||
|
||||
/* statistics can be kept for tuning/monitoring */
|
||||
#ifdef CONFIG_DYNAMIC_DEBUG
|
||||
#define EHCI_STATS
|
||||
#endif
|
||||
|
||||
struct ehci_stats {
|
||||
/* irq usage */
|
||||
unsigned long normal;
|
||||
unsigned long error;
|
||||
unsigned long iaa;
|
||||
unsigned long lost_iaa;
|
||||
|
||||
/* termination of urbs from core */
|
||||
unsigned long complete;
|
||||
unsigned long unlink;
|
||||
};
|
||||
|
||||
/*
|
||||
* Scheduling and budgeting information for periodic transfers, for both
|
||||
* high-speed devices and full/low-speed devices lying behind a TT.
|
||||
*/
|
||||
struct ehci_per_sched {
|
||||
struct usb_device *udev; /* access to the TT */
|
||||
struct usb_host_endpoint *ep;
|
||||
struct list_head ps_list; /* node on ehci_tt's ps_list */
|
||||
u16 tt_usecs; /* time on the FS/LS bus */
|
||||
u16 cs_mask; /* C-mask and S-mask bytes */
|
||||
u16 period; /* actual period in frames */
|
||||
u16 phase; /* actual phase, frame part */
|
||||
u8 bw_phase; /* same, for bandwidth
|
||||
reservation */
|
||||
u8 phase_uf; /* uframe part of the phase */
|
||||
u8 usecs, c_usecs; /* times on the HS bus */
|
||||
u8 bw_uperiod; /* period in microframes, for
|
||||
bandwidth reservation */
|
||||
u8 bw_period; /* same, in frames */
|
||||
};
|
||||
#define NO_FRAME 29999 /* frame not assigned yet */
|
||||
|
||||
/* ehci_hcd->lock guards shared data against other CPUs:
|
||||
* ehci_hcd: async, unlink, periodic (and shadow), ...
|
||||
* usb_host_endpoint: hcpriv
|
||||
* ehci_qh: qh_next, qtd_list
|
||||
* ehci_qtd: qtd_list
|
||||
*
|
||||
* Also, hold this lock when talking to HC registers or
|
||||
* when updating hw_* fields in shared qh/qtd/... structures.
|
||||
*/
|
||||
|
||||
#define EHCI_MAX_ROOT_PORTS 15 /* see HCS_N_PORTS */
|
||||
|
||||
/*
|
||||
* ehci_rh_state values of EHCI_RH_RUNNING or above mean that the
|
||||
* controller may be doing DMA. Lower values mean there's no DMA.
|
||||
*/
|
||||
enum ehci_rh_state {
|
||||
EHCI_RH_HALTED,
|
||||
EHCI_RH_SUSPENDED,
|
||||
EHCI_RH_RUNNING,
|
||||
EHCI_RH_STOPPING
|
||||
};
|
||||
|
||||
/*
|
||||
* Timer events, ordered by increasing delay length.
|
||||
* Always update event_delays_ns[] and event_handlers[] (defined in
|
||||
* ehci-timer.c) in parallel with this list.
|
||||
*/
|
||||
enum ehci_hrtimer_event {
|
||||
EHCI_HRTIMER_POLL_ASS, /* Poll for async schedule off */
|
||||
EHCI_HRTIMER_POLL_PSS, /* Poll for periodic schedule off */
|
||||
EHCI_HRTIMER_POLL_DEAD, /* Wait for dead controller to stop */
|
||||
EHCI_HRTIMER_UNLINK_INTR, /* Wait for interrupt QH unlink */
|
||||
EHCI_HRTIMER_FREE_ITDS, /* Wait for unused iTDs and siTDs */
|
||||
EHCI_HRTIMER_START_UNLINK_INTR, /* Unlink empty interrupt QHs */
|
||||
EHCI_HRTIMER_ASYNC_UNLINKS, /* Unlink empty async QHs */
|
||||
EHCI_HRTIMER_IAA_WATCHDOG, /* Handle lost IAA interrupts */
|
||||
EHCI_HRTIMER_DISABLE_PERIODIC, /* Wait to disable periodic sched */
|
||||
EHCI_HRTIMER_DISABLE_ASYNC, /* Wait to disable async sched */
|
||||
EHCI_HRTIMER_IO_WATCHDOG, /* Check for missing IRQs */
|
||||
EHCI_HRTIMER_NUM_EVENTS /* Must come last */
|
||||
};
|
||||
#define EHCI_HRTIMER_NO_EVENT 99
|
||||
|
||||
struct ehci_hcd { /* one per controller */
|
||||
/* timing support */
|
||||
enum ehci_hrtimer_event next_hrtimer_event;
|
||||
unsigned enabled_hrtimer_events;
|
||||
ktime_t hr_timeouts[EHCI_HRTIMER_NUM_EVENTS];
|
||||
struct hrtimer hrtimer;
|
||||
|
||||
int PSS_poll_count;
|
||||
int ASS_poll_count;
|
||||
int died_poll_count;
|
||||
|
||||
/* glue to PCI and HCD framework */
|
||||
struct ehci_caps __iomem *caps;
|
||||
struct ehci_regs __iomem *regs;
|
||||
struct ehci_dbg_port __iomem *debug;
|
||||
|
||||
__u32 hcs_params; /* cached register copy */
|
||||
spinlock_t lock;
|
||||
enum ehci_rh_state rh_state;
|
||||
|
||||
/* general schedule support */
|
||||
bool scanning:1;
|
||||
bool need_rescan:1;
|
||||
bool intr_unlinking:1;
|
||||
bool iaa_in_progress:1;
|
||||
bool async_unlinking:1;
|
||||
bool shutdown:1;
|
||||
struct ehci_qh *qh_scan_next;
|
||||
|
||||
/* async schedule support */
|
||||
struct ehci_qh *async;
|
||||
struct ehci_qh *dummy; /* For AMD quirk use */
|
||||
struct list_head async_unlink;
|
||||
struct list_head async_idle;
|
||||
unsigned async_unlink_cycle;
|
||||
unsigned async_count; /* async activity count */
|
||||
|
||||
/* periodic schedule support */
|
||||
#define DEFAULT_I_TDPS 1024 /* some HCs can do less */
|
||||
unsigned periodic_size;
|
||||
__hc32 *periodic; /* hw periodic table */
|
||||
dma_addr_t periodic_dma;
|
||||
struct list_head intr_qh_list;
|
||||
unsigned i_thresh; /* uframes HC might cache */
|
||||
|
||||
union ehci_shadow *pshadow; /* mirror hw periodic table */
|
||||
struct list_head intr_unlink_wait;
|
||||
struct list_head intr_unlink;
|
||||
unsigned intr_unlink_wait_cycle;
|
||||
unsigned intr_unlink_cycle;
|
||||
unsigned now_frame; /* frame from HC hardware */
|
||||
unsigned last_iso_frame; /* last frame scanned for iso */
|
||||
unsigned intr_count; /* intr activity count */
|
||||
unsigned isoc_count; /* isoc activity count */
|
||||
unsigned periodic_count; /* periodic activity count */
|
||||
unsigned uframe_periodic_max; /* max periodic time per uframe */
|
||||
|
||||
|
||||
/* list of itds & sitds completed while now_frame was still active */
|
||||
struct list_head cached_itd_list;
|
||||
struct ehci_itd *last_itd_to_free;
|
||||
struct list_head cached_sitd_list;
|
||||
struct ehci_sitd *last_sitd_to_free;
|
||||
|
||||
/* per root hub port */
|
||||
unsigned long reset_done [EHCI_MAX_ROOT_PORTS];
|
||||
|
||||
/* bit vectors (one bit per port) */
|
||||
unsigned long bus_suspended; /* which ports were
|
||||
already suspended at the start of a bus suspend */
|
||||
unsigned long companion_ports; /* which ports are
|
||||
dedicated to the companion controller */
|
||||
unsigned long owned_ports; /* which ports are
|
||||
owned by the companion during a bus suspend */
|
||||
unsigned long port_c_suspend; /* which ports have
|
||||
the change-suspend feature turned on */
|
||||
unsigned long suspended_ports; /* which ports are
|
||||
suspended */
|
||||
unsigned long resuming_ports; /* which ports have
|
||||
started to resume */
|
||||
|
||||
/* per-HC memory pools (could be per-bus, but ...) */
|
||||
struct dma_pool *qh_pool; /* qh per active urb */
|
||||
struct dma_pool *qtd_pool; /* one or more per qh */
|
||||
struct dma_pool *itd_pool; /* itd per iso urb */
|
||||
struct dma_pool *sitd_pool; /* sitd per split iso urb */
|
||||
|
||||
unsigned random_frame;
|
||||
unsigned long next_statechange;
|
||||
ktime_t last_periodic_enable;
|
||||
u32 command;
|
||||
|
||||
/* SILICON QUIRKS */
|
||||
unsigned no_selective_suspend:1;
|
||||
unsigned has_fsl_port_bug:1; /* FreeScale */
|
||||
unsigned has_fsl_hs_errata:1; /* Freescale HS quirk */
|
||||
unsigned big_endian_mmio:1;
|
||||
unsigned big_endian_desc:1;
|
||||
unsigned big_endian_capbase:1;
|
||||
unsigned has_amcc_usb23:1;
|
||||
unsigned need_io_watchdog:1;
|
||||
unsigned amd_pll_fix:1;
|
||||
unsigned use_dummy_qh:1; /* AMD Frame List table quirk*/
|
||||
unsigned has_synopsys_hc_bug:1; /* Synopsys HC */
|
||||
unsigned frame_index_bug:1; /* MosChip (AKA NetMos) */
|
||||
unsigned need_oc_pp_cycle:1; /* MPC834X port power */
|
||||
unsigned imx28_write_fix:1; /* For Freescale i.MX28 */
|
||||
|
||||
/* required for usb32 quirk */
|
||||
#define OHCI_CTRL_HCFS (3 << 6)
|
||||
#define OHCI_USB_OPER (2 << 6)
|
||||
#define OHCI_USB_SUSPEND (3 << 6)
|
||||
|
||||
#define OHCI_HCCTRL_OFFSET 0x4
|
||||
#define OHCI_HCCTRL_LEN 0x4
|
||||
__hc32 *ohci_hcctrl_reg;
|
||||
unsigned has_hostpc:1;
|
||||
unsigned has_tdi_phy_lpm:1;
|
||||
unsigned has_ppcd:1; /* support per-port change bits */
|
||||
u8 sbrn; /* packed release number */
|
||||
|
||||
/* irq statistics */
|
||||
#ifdef EHCI_STATS
|
||||
struct ehci_stats stats;
|
||||
# define COUNT(x) do { (x)++; } while (0)
|
||||
#else
|
||||
# define COUNT(x) do {} while (0)
|
||||
#endif
|
||||
|
||||
/* debug files */
|
||||
#ifdef CONFIG_DYNAMIC_DEBUG
|
||||
struct dentry *debug_dir;
|
||||
#endif
|
||||
|
||||
/* bandwidth usage */
|
||||
#define EHCI_BANDWIDTH_SIZE 64
|
||||
#define EHCI_BANDWIDTH_FRAMES (EHCI_BANDWIDTH_SIZE >> 3)
|
||||
u8 bandwidth[EHCI_BANDWIDTH_SIZE];
|
||||
/* us allocated per uframe */
|
||||
u8 tt_budget[EHCI_BANDWIDTH_SIZE];
|
||||
/* us budgeted per uframe */
|
||||
struct list_head tt_list;
|
||||
|
||||
/* platform-specific data -- must come last */
|
||||
unsigned long priv[0] __aligned(sizeof(s64));
|
||||
};
|
||||
|
||||
/* convert between an HCD pointer and the corresponding EHCI_HCD */
|
||||
static inline struct ehci_hcd *hcd_to_ehci (struct usb_hcd *hcd)
|
||||
{
|
||||
return (struct ehci_hcd *) (hcd->hcd_priv);
|
||||
}
|
||||
static inline struct usb_hcd *ehci_to_hcd (struct ehci_hcd *ehci)
|
||||
{
|
||||
return container_of ((void *) ehci, struct usb_hcd, hcd_priv);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
#include <linux/usb/ehci_def.h>
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
#define QTD_NEXT(ehci, dma) cpu_to_hc32(ehci, (u32)dma)
|
||||
|
||||
/*
|
||||
* EHCI Specification 0.95 Section 3.5
|
||||
* QTD: describe data transfer components (buffer, direction, ...)
|
||||
* See Fig 3-6 "Queue Element Transfer Descriptor Block Diagram".
|
||||
*
|
||||
* These are associated only with "QH" (Queue Head) structures,
|
||||
* used with control, bulk, and interrupt transfers.
|
||||
*/
|
||||
struct ehci_qtd {
|
||||
/* first part defined by EHCI spec */
|
||||
__hc32 hw_next; /* see EHCI 3.5.1 */
|
||||
__hc32 hw_alt_next; /* see EHCI 3.5.2 */
|
||||
__hc32 hw_token; /* see EHCI 3.5.3 */
|
||||
#define QTD_TOGGLE (1 << 31) /* data toggle */
|
||||
#define QTD_LENGTH(tok) (((tok)>>16) & 0x7fff)
|
||||
#define QTD_IOC (1 << 15) /* interrupt on complete */
|
||||
#define QTD_CERR(tok) (((tok)>>10) & 0x3)
|
||||
#define QTD_PID(tok) (((tok)>>8) & 0x3)
|
||||
#define QTD_STS_ACTIVE (1 << 7) /* HC may execute this */
|
||||
#define QTD_STS_HALT (1 << 6) /* halted on error */
|
||||
#define QTD_STS_DBE (1 << 5) /* data buffer error (in HC) */
|
||||
#define QTD_STS_BABBLE (1 << 4) /* device was babbling (qtd halted) */
|
||||
#define QTD_STS_XACT (1 << 3) /* device gave illegal response */
|
||||
#define QTD_STS_MMF (1 << 2) /* incomplete split transaction */
|
||||
#define QTD_STS_STS (1 << 1) /* split transaction state */
|
||||
#define QTD_STS_PING (1 << 0) /* issue PING? */
|
||||
|
||||
#define ACTIVE_BIT(ehci) cpu_to_hc32(ehci, QTD_STS_ACTIVE)
|
||||
#define HALT_BIT(ehci) cpu_to_hc32(ehci, QTD_STS_HALT)
|
||||
#define STATUS_BIT(ehci) cpu_to_hc32(ehci, QTD_STS_STS)
|
||||
|
||||
__hc32 hw_buf [5]; /* see EHCI 3.5.4 */
|
||||
__hc32 hw_buf_hi [5]; /* Appendix B */
|
||||
|
||||
/* the rest is HCD-private */
|
||||
dma_addr_t qtd_dma; /* qtd address */
|
||||
struct list_head qtd_list; /* sw qtd list */
|
||||
struct urb *urb; /* qtd's urb */
|
||||
size_t length; /* length of buffer */
|
||||
} __attribute__ ((aligned (32)));
|
||||
|
||||
/* mask NakCnt+T in qh->hw_alt_next */
|
||||
#define QTD_MASK(ehci) cpu_to_hc32 (ehci, ~0x1f)
|
||||
|
||||
#define IS_SHORT_READ(token) (QTD_LENGTH (token) != 0 && QTD_PID (token) == 1)
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* type tag from {qh,itd,sitd,fstn}->hw_next */
|
||||
#define Q_NEXT_TYPE(ehci,dma) ((dma) & cpu_to_hc32(ehci, 3 << 1))
|
||||
|
||||
/*
|
||||
* Now the following defines are not converted using the
|
||||
* cpu_to_le32() macro anymore, since we have to support
|
||||
* "dynamic" switching between be and le support, so that the driver
|
||||
* can be used on one system with SoC EHCI controller using big-endian
|
||||
* descriptors as well as a normal little-endian PCI EHCI controller.
|
||||
*/
|
||||
/* values for that type tag */
|
||||
#define Q_TYPE_ITD (0 << 1)
|
||||
#define Q_TYPE_QH (1 << 1)
|
||||
#define Q_TYPE_SITD (2 << 1)
|
||||
#define Q_TYPE_FSTN (3 << 1)
|
||||
|
||||
/* next async queue entry, or pointer to interrupt/periodic QH */
|
||||
#define QH_NEXT(ehci,dma) (cpu_to_hc32(ehci, (((u32)dma)&~0x01f)|Q_TYPE_QH))
|
||||
|
||||
/* for periodic/async schedules and qtd lists, mark end of list */
|
||||
#define EHCI_LIST_END(ehci) cpu_to_hc32(ehci, 1) /* "null pointer" to hw */
|
||||
|
||||
/*
|
||||
* Entries in periodic shadow table are pointers to one of four kinds
|
||||
* of data structure. That's dictated by the hardware; a type tag is
|
||||
* encoded in the low bits of the hardware's periodic schedule. Use
|
||||
* Q_NEXT_TYPE to get the tag.
|
||||
*
|
||||
* For entries in the async schedule, the type tag always says "qh".
|
||||
*/
|
||||
union ehci_shadow {
|
||||
struct ehci_qh *qh; /* Q_TYPE_QH */
|
||||
struct ehci_itd *itd; /* Q_TYPE_ITD */
|
||||
struct ehci_sitd *sitd; /* Q_TYPE_SITD */
|
||||
struct ehci_fstn *fstn; /* Q_TYPE_FSTN */
|
||||
__hc32 *hw_next; /* (all types) */
|
||||
void *ptr;
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* EHCI Specification 0.95 Section 3.6
|
||||
* QH: describes control/bulk/interrupt endpoints
|
||||
* See Fig 3-7 "Queue Head Structure Layout".
|
||||
*
|
||||
* These appear in both the async and (for interrupt) periodic schedules.
|
||||
*/
|
||||
|
||||
/* first part defined by EHCI spec */
|
||||
struct ehci_qh_hw {
|
||||
__hc32 hw_next; /* see EHCI 3.6.1 */
|
||||
__hc32 hw_info1; /* see EHCI 3.6.2 */
|
||||
#define QH_CONTROL_EP (1 << 27) /* FS/LS control endpoint */
|
||||
#define QH_HEAD (1 << 15) /* Head of async reclamation list */
|
||||
#define QH_TOGGLE_CTL (1 << 14) /* Data toggle control */
|
||||
#define QH_HIGH_SPEED (2 << 12) /* Endpoint speed */
|
||||
#define QH_LOW_SPEED (1 << 12)
|
||||
#define QH_FULL_SPEED (0 << 12)
|
||||
#define QH_INACTIVATE (1 << 7) /* Inactivate on next transaction */
|
||||
__hc32 hw_info2; /* see EHCI 3.6.2 */
|
||||
#define QH_SMASK 0x000000ff
|
||||
#define QH_CMASK 0x0000ff00
|
||||
#define QH_HUBADDR 0x007f0000
|
||||
#define QH_HUBPORT 0x3f800000
|
||||
#define QH_MULT 0xc0000000
|
||||
__hc32 hw_current; /* qtd list - see EHCI 3.6.4 */
|
||||
|
||||
/* qtd overlay (hardware parts of a struct ehci_qtd) */
|
||||
__hc32 hw_qtd_next;
|
||||
__hc32 hw_alt_next;
|
||||
__hc32 hw_token;
|
||||
__hc32 hw_buf [5];
|
||||
__hc32 hw_buf_hi [5];
|
||||
} __attribute__ ((aligned(32)));
|
||||
|
||||
struct ehci_qh {
|
||||
struct ehci_qh_hw *hw; /* Must come first */
|
||||
/* the rest is HCD-private */
|
||||
dma_addr_t qh_dma; /* address of qh */
|
||||
union ehci_shadow qh_next; /* ptr to qh; or periodic */
|
||||
struct list_head qtd_list; /* sw qtd list */
|
||||
struct list_head intr_node; /* list of intr QHs */
|
||||
struct ehci_qtd *dummy;
|
||||
struct list_head unlink_node;
|
||||
struct ehci_per_sched ps; /* scheduling info */
|
||||
|
||||
unsigned unlink_cycle;
|
||||
|
||||
u8 qh_state;
|
||||
#define QH_STATE_LINKED 1 /* HC sees this */
|
||||
#define QH_STATE_UNLINK 2 /* HC may still see this */
|
||||
#define QH_STATE_IDLE 3 /* HC doesn't see this */
|
||||
#define QH_STATE_UNLINK_WAIT 4 /* LINKED and on unlink q */
|
||||
#define QH_STATE_COMPLETING 5 /* don't touch token.HALT */
|
||||
|
||||
u8 xacterrs; /* XactErr retry counter */
|
||||
#define QH_XACTERR_MAX 32 /* XactErr retry limit */
|
||||
|
||||
u8 gap_uf; /* uframes split/csplit gap */
|
||||
|
||||
unsigned is_out:1; /* bulk or intr OUT */
|
||||
unsigned clearing_tt:1; /* Clear-TT-Buf in progress */
|
||||
unsigned dequeue_during_giveback:1;
|
||||
unsigned exception:1; /* got a fault, or an unlink
|
||||
was requested */
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* description of one iso transaction (up to 3 KB data if highspeed) */
|
||||
struct ehci_iso_packet {
|
||||
/* These will be copied to iTD when scheduling */
|
||||
u64 bufp; /* itd->hw_bufp{,_hi}[pg] |= */
|
||||
__hc32 transaction; /* itd->hw_transaction[i] |= */
|
||||
u8 cross; /* buf crosses pages */
|
||||
/* for full speed OUT splits */
|
||||
u32 buf1;
|
||||
};
|
||||
|
||||
/* temporary schedule data for packets from iso urbs (both speeds)
|
||||
* each packet is one logical usb transaction to the device (not TT),
|
||||
* beginning at stream->next_uframe
|
||||
*/
|
||||
struct ehci_iso_sched {
|
||||
struct list_head td_list;
|
||||
unsigned span;
|
||||
unsigned first_packet;
|
||||
struct ehci_iso_packet packet [0];
|
||||
};
|
||||
|
||||
/*
|
||||
* ehci_iso_stream - groups all (s)itds for this endpoint.
|
||||
* acts like a qh would, if EHCI had them for ISO.
|
||||
*/
|
||||
struct ehci_iso_stream {
|
||||
/* first field matches ehci_hq, but is NULL */
|
||||
struct ehci_qh_hw *hw;
|
||||
|
||||
u8 bEndpointAddress;
|
||||
u8 highspeed;
|
||||
struct list_head td_list; /* queued itds/sitds */
|
||||
struct list_head free_list; /* list of unused itds/sitds */
|
||||
|
||||
/* output of (re)scheduling */
|
||||
struct ehci_per_sched ps; /* scheduling info */
|
||||
unsigned next_uframe;
|
||||
__hc32 splits;
|
||||
|
||||
/* the rest is derived from the endpoint descriptor,
|
||||
* including the extra info for hw_bufp[0..2]
|
||||
*/
|
||||
u16 uperiod; /* period in uframes */
|
||||
u16 maxp;
|
||||
unsigned bandwidth;
|
||||
|
||||
/* This is used to initialize iTD's hw_bufp fields */
|
||||
__hc32 buf0;
|
||||
__hc32 buf1;
|
||||
__hc32 buf2;
|
||||
|
||||
/* this is used to initialize sITD's tt info */
|
||||
__hc32 address;
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* EHCI Specification 0.95 Section 3.3
|
||||
* Fig 3-4 "Isochronous Transaction Descriptor (iTD)"
|
||||
*
|
||||
* Schedule records for high speed iso xfers
|
||||
*/
|
||||
struct ehci_itd {
|
||||
/* first part defined by EHCI spec */
|
||||
__hc32 hw_next; /* see EHCI 3.3.1 */
|
||||
__hc32 hw_transaction [8]; /* see EHCI 3.3.2 */
|
||||
#define EHCI_ISOC_ACTIVE (1<<31) /* activate transfer this slot */
|
||||
#define EHCI_ISOC_BUF_ERR (1<<30) /* Data buffer error */
|
||||
#define EHCI_ISOC_BABBLE (1<<29) /* babble detected */
|
||||
#define EHCI_ISOC_XACTERR (1<<28) /* XactErr - transaction error */
|
||||
#define EHCI_ITD_LENGTH(tok) (((tok)>>16) & 0x0fff)
|
||||
#define EHCI_ITD_IOC (1 << 15) /* interrupt on complete */
|
||||
|
||||
#define ITD_ACTIVE(ehci) cpu_to_hc32(ehci, EHCI_ISOC_ACTIVE)
|
||||
|
||||
__hc32 hw_bufp [7]; /* see EHCI 3.3.3 */
|
||||
__hc32 hw_bufp_hi [7]; /* Appendix B */
|
||||
|
||||
/* the rest is HCD-private */
|
||||
dma_addr_t itd_dma; /* for this itd */
|
||||
union ehci_shadow itd_next; /* ptr to periodic q entry */
|
||||
|
||||
struct urb *urb;
|
||||
struct ehci_iso_stream *stream; /* endpoint's queue */
|
||||
struct list_head itd_list; /* list of stream's itds */
|
||||
|
||||
/* any/all hw_transactions here may be used by that urb */
|
||||
unsigned frame; /* where scheduled */
|
||||
unsigned pg;
|
||||
unsigned index[8]; /* in urb->iso_frame_desc */
|
||||
} __attribute__ ((aligned (32)));
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* EHCI Specification 0.95 Section 3.4
|
||||
* siTD, aka split-transaction isochronous Transfer Descriptor
|
||||
* ... describe full speed iso xfers through TT in hubs
|
||||
* see Figure 3-5 "Split-transaction Isochronous Transaction Descriptor (siTD)
|
||||
*/
|
||||
struct ehci_sitd {
|
||||
/* first part defined by EHCI spec */
|
||||
__hc32 hw_next;
|
||||
/* uses bit field macros above - see EHCI 0.95 Table 3-8 */
|
||||
__hc32 hw_fullspeed_ep; /* EHCI table 3-9 */
|
||||
__hc32 hw_uframe; /* EHCI table 3-10 */
|
||||
__hc32 hw_results; /* EHCI table 3-11 */
|
||||
#define SITD_IOC (1 << 31) /* interrupt on completion */
|
||||
#define SITD_PAGE (1 << 30) /* buffer 0/1 */
|
||||
#define SITD_LENGTH(x) (0x3ff & ((x)>>16))
|
||||
#define SITD_STS_ACTIVE (1 << 7) /* HC may execute this */
|
||||
#define SITD_STS_ERR (1 << 6) /* error from TT */
|
||||
#define SITD_STS_DBE (1 << 5) /* data buffer error (in HC) */
|
||||
#define SITD_STS_BABBLE (1 << 4) /* device was babbling */
|
||||
#define SITD_STS_XACT (1 << 3) /* illegal IN response */
|
||||
#define SITD_STS_MMF (1 << 2) /* incomplete split transaction */
|
||||
#define SITD_STS_STS (1 << 1) /* split transaction state */
|
||||
|
||||
#define SITD_ACTIVE(ehci) cpu_to_hc32(ehci, SITD_STS_ACTIVE)
|
||||
|
||||
__hc32 hw_buf [2]; /* EHCI table 3-12 */
|
||||
__hc32 hw_backpointer; /* EHCI table 3-13 */
|
||||
__hc32 hw_buf_hi [2]; /* Appendix B */
|
||||
|
||||
/* the rest is HCD-private */
|
||||
dma_addr_t sitd_dma;
|
||||
union ehci_shadow sitd_next; /* ptr to periodic q entry */
|
||||
|
||||
struct urb *urb;
|
||||
struct ehci_iso_stream *stream; /* endpoint's queue */
|
||||
struct list_head sitd_list; /* list of stream's sitds */
|
||||
unsigned frame;
|
||||
unsigned index;
|
||||
} __attribute__ ((aligned (32)));
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* EHCI Specification 0.96 Section 3.7
|
||||
* Periodic Frame Span Traversal Node (FSTN)
|
||||
*
|
||||
* Manages split interrupt transactions (using TT) that span frame boundaries
|
||||
* into uframes 0/1; see 4.12.2.2. In those uframes, a "save place" FSTN
|
||||
* makes the HC jump (back) to a QH to scan for fs/ls QH completions until
|
||||
* it hits a "restore" FSTN; then it returns to finish other uframe 0/1 work.
|
||||
*/
|
||||
struct ehci_fstn {
|
||||
__hc32 hw_next; /* any periodic q entry */
|
||||
__hc32 hw_prev; /* qh or EHCI_LIST_END */
|
||||
|
||||
/* the rest is HCD-private */
|
||||
dma_addr_t fstn_dma;
|
||||
union ehci_shadow fstn_next; /* ptr to periodic q entry */
|
||||
} __attribute__ ((aligned (32)));
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* USB-2.0 Specification Sections 11.14 and 11.18
|
||||
* Scheduling and budgeting split transactions using TTs
|
||||
*
|
||||
* A hub can have a single TT for all its ports, or multiple TTs (one for each
|
||||
* port). The bandwidth and budgeting information for the full/low-speed bus
|
||||
* below each TT is self-contained and independent of the other TTs or the
|
||||
* high-speed bus.
|
||||
*
|
||||
* "Bandwidth" refers to the number of microseconds on the FS/LS bus allocated
|
||||
* to an interrupt or isochronous endpoint for each frame. "Budget" refers to
|
||||
* the best-case estimate of the number of full-speed bytes allocated to an
|
||||
* endpoint for each microframe within an allocated frame.
|
||||
*
|
||||
* Removal of an endpoint invalidates a TT's budget. Instead of trying to
|
||||
* keep an up-to-date record, we recompute the budget when it is needed.
|
||||
*/
|
||||
|
||||
struct ehci_tt {
|
||||
u16 bandwidth[EHCI_BANDWIDTH_FRAMES];
|
||||
|
||||
struct list_head tt_list; /* List of all ehci_tt's */
|
||||
struct list_head ps_list; /* Items using this TT */
|
||||
struct usb_tt *usb_tt;
|
||||
int tt_port; /* TT port number */
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* Prepare the PORTSC wakeup flags during controller suspend/resume */
|
||||
|
||||
#define ehci_prepare_ports_for_controller_suspend(ehci, do_wakeup) \
|
||||
ehci_adjust_port_wakeup_flags(ehci, true, do_wakeup);
|
||||
|
||||
#define ehci_prepare_ports_for_controller_resume(ehci) \
|
||||
ehci_adjust_port_wakeup_flags(ehci, false, false);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
#ifdef CONFIG_USB_EHCI_ROOT_HUB_TT
|
||||
|
||||
/*
|
||||
* Some EHCI controllers have a Transaction Translator built into the
|
||||
* root hub. This is a non-standard feature. Each controller will need
|
||||
* to add code to the following inline functions, and call them as
|
||||
* needed (mostly in root hub code).
|
||||
*/
|
||||
|
||||
#define ehci_is_TDI(e) (ehci_to_hcd(e)->has_tt)
|
||||
|
||||
/* Returns the speed of a device attached to a port on the root hub. */
|
||||
static inline unsigned int
|
||||
ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
|
||||
{
|
||||
if (ehci_is_TDI(ehci)) {
|
||||
switch ((portsc >> (ehci->has_hostpc ? 25 : 26)) & 3) {
|
||||
case 0:
|
||||
return 0;
|
||||
case 1:
|
||||
return USB_PORT_STAT_LOW_SPEED;
|
||||
case 2:
|
||||
default:
|
||||
return USB_PORT_STAT_HIGH_SPEED;
|
||||
}
|
||||
}
|
||||
return USB_PORT_STAT_HIGH_SPEED;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define ehci_is_TDI(e) (0)
|
||||
|
||||
#define ehci_port_speed(ehci, portsc) USB_PORT_STAT_HIGH_SPEED
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
#ifdef CONFIG_PPC_83xx
|
||||
/* Some Freescale processors have an erratum in which the TT
|
||||
* port number in the queue head was 0..N-1 instead of 1..N.
|
||||
*/
|
||||
#define ehci_has_fsl_portno_bug(e) ((e)->has_fsl_port_bug)
|
||||
#else
|
||||
#define ehci_has_fsl_portno_bug(e) (0)
|
||||
#endif
|
||||
|
||||
#define PORTSC_FSL_PFSC 24 /* Port Force Full-Speed Connect */
|
||||
|
||||
#if defined(CONFIG_PPC_85xx)
|
||||
/* Some Freescale processors have an erratum (USB A-005275) in which
|
||||
* incoming packets get corrupted in HS mode
|
||||
*/
|
||||
#define ehci_has_fsl_hs_errata(e) ((e)->has_fsl_hs_errata)
|
||||
#else
|
||||
#define ehci_has_fsl_hs_errata(e) (0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* While most USB host controllers implement their registers in
|
||||
* little-endian format, a minority (celleb companion chip) implement
|
||||
* them in big endian format.
|
||||
*
|
||||
* This attempts to support either format at compile time without a
|
||||
* runtime penalty, or both formats with the additional overhead
|
||||
* of checking a flag bit.
|
||||
*
|
||||
* ehci_big_endian_capbase is a special quirk for controllers that
|
||||
* implement the HC capability registers as separate registers and not
|
||||
* as fields of a 32-bit register.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
|
||||
#define ehci_big_endian_mmio(e) ((e)->big_endian_mmio)
|
||||
#define ehci_big_endian_capbase(e) ((e)->big_endian_capbase)
|
||||
#else
|
||||
#define ehci_big_endian_mmio(e) 0
|
||||
#define ehci_big_endian_capbase(e) 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Big-endian read/write functions are arch-specific.
|
||||
* Other arches can be added if/when they're needed.
|
||||
*/
|
||||
#if defined(CONFIG_ARM) && defined(CONFIG_ARCH_IXP4XX)
|
||||
#define readl_be(addr) __raw_readl((__force unsigned *)addr)
|
||||
#define writel_be(val, addr) __raw_writel(val, (__force unsigned *)addr)
|
||||
#endif
|
||||
|
||||
static inline unsigned int ehci_readl(const struct ehci_hcd *ehci,
|
||||
__u32 __iomem * regs)
|
||||
{
|
||||
#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
|
||||
return ehci_big_endian_mmio(ehci) ?
|
||||
readl_be(regs) :
|
||||
readl(regs);
|
||||
#else
|
||||
return readl(regs);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SOC_IMX28
|
||||
static inline void imx28_ehci_writel(const unsigned int val,
|
||||
volatile __u32 __iomem *addr)
|
||||
{
|
||||
__asm__ ("swp %0, %0, [%1]" : : "r"(val), "r"(addr));
|
||||
}
|
||||
#else
|
||||
static inline void imx28_ehci_writel(const unsigned int val,
|
||||
volatile __u32 __iomem *addr)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
static inline void ehci_writel(const struct ehci_hcd *ehci,
|
||||
const unsigned int val, __u32 __iomem *regs)
|
||||
{
|
||||
#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
|
||||
ehci_big_endian_mmio(ehci) ?
|
||||
writel_be(val, regs) :
|
||||
writel(val, regs);
|
||||
#else
|
||||
if (ehci->imx28_write_fix)
|
||||
imx28_ehci_writel(val, regs);
|
||||
else
|
||||
writel(val, regs);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* On certain ppc-44x SoC there is a HW issue, that could only worked around with
|
||||
* explicit suspend/operate of OHCI. This function hereby makes sense only on that arch.
|
||||
* Other common bits are dependent on has_amcc_usb23 quirk flag.
|
||||
*/
|
||||
#ifdef CONFIG_44x
|
||||
static inline void set_ohci_hcfs(struct ehci_hcd *ehci, int operational)
|
||||
{
|
||||
u32 hc_control;
|
||||
|
||||
hc_control = (readl_be(ehci->ohci_hcctrl_reg) & ~OHCI_CTRL_HCFS);
|
||||
if (operational)
|
||||
hc_control |= OHCI_USB_OPER;
|
||||
else
|
||||
hc_control |= OHCI_USB_SUSPEND;
|
||||
|
||||
writel_be(hc_control, ehci->ohci_hcctrl_reg);
|
||||
(void) readl_be(ehci->ohci_hcctrl_reg);
|
||||
}
|
||||
#else
|
||||
static inline void set_ohci_hcfs(struct ehci_hcd *ehci, int operational)
|
||||
{ }
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* The AMCC 440EPx not only implements its EHCI registers in big-endian
|
||||
* format, but also its DMA data structures (descriptors).
|
||||
*
|
||||
* EHCI controllers accessed through PCI work normally (little-endian
|
||||
* everywhere), so we won't bother supporting a BE-only mode for now.
|
||||
*/
|
||||
#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_DESC
|
||||
#define ehci_big_endian_desc(e) ((e)->big_endian_desc)
|
||||
|
||||
/* cpu to ehci */
|
||||
static inline __hc32 cpu_to_hc32 (const struct ehci_hcd *ehci, const u32 x)
|
||||
{
|
||||
return ehci_big_endian_desc(ehci)
|
||||
? (__force __hc32)cpu_to_be32(x)
|
||||
: (__force __hc32)cpu_to_le32(x);
|
||||
}
|
||||
|
||||
/* ehci to cpu */
|
||||
static inline u32 hc32_to_cpu (const struct ehci_hcd *ehci, const __hc32 x)
|
||||
{
|
||||
return ehci_big_endian_desc(ehci)
|
||||
? be32_to_cpu((__force __be32)x)
|
||||
: le32_to_cpu((__force __le32)x);
|
||||
}
|
||||
|
||||
static inline u32 hc32_to_cpup (const struct ehci_hcd *ehci, const __hc32 *x)
|
||||
{
|
||||
return ehci_big_endian_desc(ehci)
|
||||
? be32_to_cpup((__force __be32 *)x)
|
||||
: le32_to_cpup((__force __le32 *)x);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* cpu to ehci */
|
||||
static inline __hc32 cpu_to_hc32 (const struct ehci_hcd *ehci, const u32 x)
|
||||
{
|
||||
return cpu_to_le32(x);
|
||||
}
|
||||
|
||||
/* ehci to cpu */
|
||||
static inline u32 hc32_to_cpu (const struct ehci_hcd *ehci, const __hc32 x)
|
||||
{
|
||||
return le32_to_cpu(x);
|
||||
}
|
||||
|
||||
static inline u32 hc32_to_cpup (const struct ehci_hcd *ehci, const __hc32 *x)
|
||||
{
|
||||
return le32_to_cpup(x);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
#define ehci_dbg(ehci, fmt, args...) \
|
||||
dev_dbg(ehci_to_hcd(ehci)->self.controller , fmt , ## args)
|
||||
#define ehci_err(ehci, fmt, args...) \
|
||||
dev_err(ehci_to_hcd(ehci)->self.controller , fmt , ## args)
|
||||
#define ehci_info(ehci, fmt, args...) \
|
||||
dev_info(ehci_to_hcd(ehci)->self.controller , fmt , ## args)
|
||||
#define ehci_warn(ehci, fmt, args...) \
|
||||
dev_warn(ehci_to_hcd(ehci)->self.controller , fmt , ## args)
|
||||
|
||||
|
||||
#ifndef CONFIG_DYNAMIC_DEBUG
|
||||
#define STUB_DEBUG_FILES
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* Declarations of things exported for use by ehci platform drivers */
|
||||
|
||||
struct ehci_driver_overrides {
|
||||
size_t extra_priv_size;
|
||||
int (*reset)(struct usb_hcd *hcd);
|
||||
int (*port_power)(struct usb_hcd *hcd,
|
||||
int portnum, bool enable);
|
||||
};
|
||||
|
||||
extern void ehci_init_driver(struct hc_driver *drv,
|
||||
const struct ehci_driver_overrides *over);
|
||||
extern int ehci_setup(struct usb_hcd *hcd);
|
||||
extern int ehci_handshake(struct ehci_hcd *ehci, void __iomem *ptr,
|
||||
u32 mask, u32 done, int usec);
|
||||
extern int ehci_reset(struct ehci_hcd *ehci);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
extern int ehci_suspend(struct usb_hcd *hcd, bool do_wakeup);
|
||||
extern int ehci_resume(struct usb_hcd *hcd, bool force_reset);
|
||||
extern void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
|
||||
bool suspending, bool do_wakeup);
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
extern int ehci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
||||
u16 wIndex, char *buf, u16 wLength);
|
||||
|
||||
#endif /* __LINUX_EHCI_HCD_H */
|
||||
1105
addons/ehci-pci/src/4.4.180/pci-quirks.c
Normal file
1105
addons/ehci-pci/src/4.4.180/pci-quirks.c
Normal file
File diff suppressed because it is too large
Load Diff
26
addons/ehci-pci/src/4.4.180/pci-quirks.h
Normal file
26
addons/ehci-pci/src/4.4.180/pci-quirks.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#ifndef __LINUX_USB_PCI_QUIRKS_H
|
||||
#define __LINUX_USB_PCI_QUIRKS_H
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
void uhci_reset_hc(struct pci_dev *pdev, unsigned long base);
|
||||
int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base);
|
||||
int usb_amd_find_chipset_info(void);
|
||||
int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *pdev);
|
||||
bool usb_amd_hang_symptom_quirk(void);
|
||||
bool usb_amd_prefetch_quirk(void);
|
||||
void usb_amd_dev_put(void);
|
||||
void usb_amd_quirk_pll_disable(void);
|
||||
void usb_amd_quirk_pll_enable(void);
|
||||
void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev);
|
||||
void usb_disable_xhci_ports(struct pci_dev *xhci_pdev);
|
||||
void sb800_prefetch(struct device *dev, int on);
|
||||
#else
|
||||
struct pci_dev;
|
||||
static inline void usb_amd_quirk_pll_disable(void) {}
|
||||
static inline void usb_amd_quirk_pll_enable(void) {}
|
||||
static inline void usb_amd_dev_put(void) {}
|
||||
static inline void usb_disable_xhci_ports(struct pci_dev *xhci_pdev) {}
|
||||
static inline void sb800_prefetch(struct device *dev, int on) {}
|
||||
#endif /* CONFIG_PCI */
|
||||
|
||||
#endif /* __LINUX_USB_PCI_QUIRKS_H */
|
||||
156
addons/ehci-pci/src/4.4.180/xhci-ext-caps.h
Normal file
156
addons/ehci-pci/src/4.4.180/xhci-ext-caps.h
Normal file
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* xHCI host controller driver
|
||||
*
|
||||
* Copyright (C) 2008 Intel Corp.
|
||||
*
|
||||
* Author: Sarah Sharp
|
||||
* Some code borrowed from the Linux EHCI driver.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
/* Up to 16 ms to halt an HC */
|
||||
#define XHCI_MAX_HALT_USEC (16*1000)
|
||||
/* HC not running - set to 1 when run/stop bit is cleared. */
|
||||
#define XHCI_STS_HALT (1<<0)
|
||||
|
||||
/* HCCPARAMS offset from PCI base address */
|
||||
#define XHCI_HCC_PARAMS_OFFSET 0x10
|
||||
/* HCCPARAMS contains the first extended capability pointer */
|
||||
#define XHCI_HCC_EXT_CAPS(p) (((p)>>16)&0xffff)
|
||||
|
||||
/* Command and Status registers offset from the Operational Registers address */
|
||||
#define XHCI_CMD_OFFSET 0x00
|
||||
#define XHCI_STS_OFFSET 0x04
|
||||
|
||||
#define XHCI_MAX_EXT_CAPS 50
|
||||
|
||||
/* Capability Register */
|
||||
/* bits 7:0 - how long is the Capabilities register */
|
||||
#define XHCI_HC_LENGTH(p) (((p)>>00)&0x00ff)
|
||||
|
||||
/* Extended capability register fields */
|
||||
#define XHCI_EXT_CAPS_ID(p) (((p)>>0)&0xff)
|
||||
#define XHCI_EXT_CAPS_NEXT(p) (((p)>>8)&0xff)
|
||||
#define XHCI_EXT_CAPS_VAL(p) ((p)>>16)
|
||||
/* Extended capability IDs - ID 0 reserved */
|
||||
#define XHCI_EXT_CAPS_LEGACY 1
|
||||
#define XHCI_EXT_CAPS_PROTOCOL 2
|
||||
#define XHCI_EXT_CAPS_PM 3
|
||||
#define XHCI_EXT_CAPS_VIRT 4
|
||||
#define XHCI_EXT_CAPS_ROUTE 5
|
||||
/* IDs 6-9 reserved */
|
||||
#define XHCI_EXT_CAPS_DEBUG 10
|
||||
/* USB Legacy Support Capability - section 7.1.1 */
|
||||
#define XHCI_HC_BIOS_OWNED (1 << 16)
|
||||
#define XHCI_HC_OS_OWNED (1 << 24)
|
||||
|
||||
/* USB Legacy Support Capability - section 7.1.1 */
|
||||
/* Add this offset, plus the value of xECP in HCCPARAMS to the base address */
|
||||
#define XHCI_LEGACY_SUPPORT_OFFSET (0x00)
|
||||
|
||||
/* USB Legacy Support Control and Status Register - section 7.1.2 */
|
||||
/* Add this offset, plus the value of xECP in HCCPARAMS to the base address */
|
||||
#define XHCI_LEGACY_CONTROL_OFFSET (0x04)
|
||||
/* bits 1:3, 5:12, and 17:19 need to be preserved; bits 21:28 should be zero */
|
||||
#define XHCI_LEGACY_DISABLE_SMI ((0x7 << 1) + (0xff << 5) + (0x7 << 17))
|
||||
#define XHCI_LEGACY_SMI_EVENTS (0x7 << 29)
|
||||
|
||||
/* USB 2.0 xHCI 0.96 L1C capability - section 7.2.2.1.3.2 */
|
||||
#define XHCI_L1C (1 << 16)
|
||||
|
||||
/* USB 2.0 xHCI 1.0 hardware LMP capability - section 7.2.2.1.3.2 */
|
||||
#define XHCI_HLC (1 << 19)
|
||||
#define XHCI_BLC (1 << 20)
|
||||
|
||||
/* command register values to disable interrupts and halt the HC */
|
||||
/* start/stop HC execution - do not write unless HC is halted*/
|
||||
#define XHCI_CMD_RUN (1 << 0)
|
||||
/* Event Interrupt Enable - get irq when EINT bit is set in USBSTS register */
|
||||
#define XHCI_CMD_EIE (1 << 2)
|
||||
/* Host System Error Interrupt Enable - get irq when HSEIE bit set in USBSTS */
|
||||
#define XHCI_CMD_HSEIE (1 << 3)
|
||||
/* Enable Wrap Event - '1' means xHC generates an event when MFINDEX wraps. */
|
||||
#define XHCI_CMD_EWE (1 << 10)
|
||||
|
||||
#define XHCI_IRQS (XHCI_CMD_EIE | XHCI_CMD_HSEIE | XHCI_CMD_EWE)
|
||||
|
||||
/* true: Controller Not Ready to accept doorbell or op reg writes after reset */
|
||||
#define XHCI_STS_CNR (1 << 11)
|
||||
|
||||
#include <linux/io.h>
|
||||
|
||||
/**
|
||||
* Return the next extended capability pointer register.
|
||||
*
|
||||
* @base PCI register base address.
|
||||
*
|
||||
* @ext_offset Offset of the 32-bit register that contains the extended
|
||||
* capabilites pointer. If searching for the first extended capability, pass
|
||||
* in XHCI_HCC_PARAMS_OFFSET. If searching for the next extended capability,
|
||||
* pass in the offset of the current extended capability register.
|
||||
*
|
||||
* Returns 0 if there is no next extended capability register or returns the register offset
|
||||
* from the PCI registers base address.
|
||||
*/
|
||||
static inline int xhci_find_next_cap_offset(void __iomem *base, int ext_offset)
|
||||
{
|
||||
u32 next;
|
||||
|
||||
next = readl(base + ext_offset);
|
||||
|
||||
if (ext_offset == XHCI_HCC_PARAMS_OFFSET) {
|
||||
/* Find the first extended capability */
|
||||
next = XHCI_HCC_EXT_CAPS(next);
|
||||
ext_offset = 0;
|
||||
} else {
|
||||
/* Find the next extended capability */
|
||||
next = XHCI_EXT_CAPS_NEXT(next);
|
||||
}
|
||||
|
||||
if (!next)
|
||||
return 0;
|
||||
/*
|
||||
* Address calculation from offset of extended capabilities
|
||||
* (or HCCPARAMS) register - see section 5.3.6 and section 7.
|
||||
*/
|
||||
return ext_offset + (next << 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the offset of the extended capabilities with capability ID id.
|
||||
*
|
||||
* @base PCI MMIO registers base address.
|
||||
* @ext_offset Offset from base of the first extended capability to look at,
|
||||
* or the address of HCCPARAMS.
|
||||
* @id Extended capability ID to search for.
|
||||
*
|
||||
* This uses an arbitrary limit of XHCI_MAX_EXT_CAPS extended capabilities
|
||||
* to make sure that the list doesn't contain a loop.
|
||||
*/
|
||||
static inline int xhci_find_ext_cap_by_id(void __iomem *base, int ext_offset, int id)
|
||||
{
|
||||
u32 val;
|
||||
int limit = XHCI_MAX_EXT_CAPS;
|
||||
|
||||
while (ext_offset && limit > 0) {
|
||||
val = readl(base + ext_offset);
|
||||
if (XHCI_EXT_CAPS_ID(val) == id)
|
||||
break;
|
||||
ext_offset = xhci_find_next_cap_offset(base, ext_offset);
|
||||
limit--;
|
||||
}
|
||||
if (limit > 0)
|
||||
return ext_offset;
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user