mirror of
https://github.com/fbelavenuto/arpl.git
synced 2026-01-16 01:12:06 +08:00
first commit
This commit is contained in:
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