kernel: USB update from stlinux24_217
This commit is contained in:
@@ -41,7 +41,7 @@
|
||||
* (host controller _Structural_ parameters)
|
||||
* see EHCI spec, Table 2-4 for each value
|
||||
*/
|
||||
static void dbg_hcs_params (struct ehci_hcd *ehci, char *label)
|
||||
static inline void dbg_hcs_params(struct ehci_hcd *ehci, char *label)
|
||||
{
|
||||
u32 params = ehci_readl(ehci, &ehci->caps->hcs_params);
|
||||
|
||||
@@ -85,7 +85,7 @@ static inline void dbg_hcs_params (struct ehci_hcd *ehci, char *label) {}
|
||||
* (host controller _Capability_ parameters)
|
||||
* see EHCI Spec, Table 2-5 for each value
|
||||
* */
|
||||
static void dbg_hcc_params (struct ehci_hcd *ehci, char *label)
|
||||
static inline void dbg_hcc_params(struct ehci_hcd *ehci, char *label)
|
||||
{
|
||||
u32 params = ehci_readl(ehci, &ehci->caps->hcc_params);
|
||||
|
||||
|
@@ -84,7 +84,8 @@ static const char hcd_name [] = "ehci_hcd";
|
||||
#define EHCI_IAA_MSECS 10 /* arbitrary */
|
||||
#define EHCI_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */
|
||||
#define EHCI_ASYNC_JIFFIES (HZ/20) /* async idle timeout */
|
||||
#define EHCI_SHRINK_FRAMES 5 /* async qh unlink delay */
|
||||
#define EHCI_SHRINK_JIFFIES (DIV_ROUND_UP(HZ, 200) + 1)
|
||||
/* 200-ms async qh unlink delay */
|
||||
|
||||
/* Initial IRQ latency: faster than hw default */
|
||||
static int log2_irq_thresh = 0; // 0 to 6
|
||||
@@ -139,10 +140,7 @@ timer_action(struct ehci_hcd *ehci, enum ehci_timer_action action)
|
||||
break;
|
||||
/* case TIMER_ASYNC_SHRINK: */
|
||||
default:
|
||||
/* add a jiffie since we synch against the
|
||||
* 8 KHz uframe counter.
|
||||
*/
|
||||
t = DIV_ROUND_UP(EHCI_SHRINK_FRAMES * HZ, 1000) + 1;
|
||||
t = EHCI_SHRINK_JIFFIES;
|
||||
break;
|
||||
}
|
||||
mod_timer(&ehci->watchdog, t + jiffies);
|
||||
@@ -432,7 +430,7 @@ static void ehci_shutdown(struct usb_hcd *hcd)
|
||||
spin_unlock_irq(&ehci->lock);
|
||||
}
|
||||
|
||||
static void ehci_port_power (struct ehci_hcd *ehci, int is_on)
|
||||
static inline void ehci_port_power(struct ehci_hcd *ehci, int is_on)
|
||||
{
|
||||
unsigned port;
|
||||
|
||||
|
@@ -264,7 +264,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
|
||||
u32 temp;
|
||||
u32 power_okay;
|
||||
int i;
|
||||
u8 resume_needed = 0;
|
||||
unsigned long resume_needed = 0;
|
||||
|
||||
if (time_before (jiffies, ehci->next_statechange))
|
||||
msleep(5);
|
||||
@@ -328,7 +328,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
|
||||
if (test_bit(i, &ehci->bus_suspended) &&
|
||||
(temp & PORT_SUSPEND)) {
|
||||
temp |= PORT_RESUME;
|
||||
resume_needed = 1;
|
||||
set_bit(i, &resume_needed);
|
||||
}
|
||||
ehci_writel(ehci, temp, &ehci->regs->port_status [i]);
|
||||
}
|
||||
@@ -343,8 +343,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
|
||||
i = HCS_N_PORTS (ehci->hcs_params);
|
||||
while (i--) {
|
||||
temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
|
||||
if (test_bit(i, &ehci->bus_suspended) &&
|
||||
(temp & PORT_SUSPEND)) {
|
||||
if (test_bit(i, &resume_needed)) {
|
||||
temp &= ~(PORT_RWC_BITS | PORT_RESUME);
|
||||
ehci_writel(ehci, temp, &ehci->regs->port_status [i]);
|
||||
ehci_vdbg (ehci, "resumed port %d\n", i + 1);
|
||||
@@ -779,10 +778,11 @@ static int ehci_hub_control (
|
||||
* power switching; they're allowed to just limit the
|
||||
* current. khubd will turn the power back on.
|
||||
*/
|
||||
if (HCS_PPC (ehci->hcs_params)){
|
||||
if ((temp & PORT_OC) && HCS_PPC(ehci->hcs_params)) {
|
||||
ehci_writel(ehci,
|
||||
temp & ~(PORT_RWC_BITS | PORT_POWER),
|
||||
status_reg);
|
||||
temp = ehci_readl(ehci, status_reg);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -103,7 +103,7 @@ qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd)
|
||||
if (!(hw->hw_info1 & cpu_to_hc32(ehci, 1 << 14))) {
|
||||
unsigned is_out, epnum;
|
||||
|
||||
is_out = !(qtd->hw_token & cpu_to_hc32(ehci, 1 << 8));
|
||||
is_out = qh->is_out;
|
||||
epnum = (hc32_to_cpup(ehci, &hw->hw_info1) >> 8) & 0x0f;
|
||||
if (unlikely (!usb_gettoggle (qh->dev, epnum, is_out))) {
|
||||
hw->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE);
|
||||
@@ -936,6 +936,7 @@ done:
|
||||
hw = qh->hw;
|
||||
hw->hw_info1 = cpu_to_hc32(ehci, info1);
|
||||
hw->hw_info2 = cpu_to_hc32(ehci, info2);
|
||||
qh->is_out = !is_input;
|
||||
usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1);
|
||||
qh_refresh (ehci, qh);
|
||||
return qh;
|
||||
@@ -1216,6 +1217,8 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
|
||||
|
||||
prev->hw->hw_next = qh->hw->hw_next;
|
||||
prev->qh_next = qh->qh_next;
|
||||
if (ehci->qh_scan_next == qh)
|
||||
ehci->qh_scan_next = qh->qh_next.qh;
|
||||
wmb ();
|
||||
|
||||
/* If the controller isn't running, we don't have to wait for it */
|
||||
@@ -1241,53 +1244,49 @@ static void scan_async (struct ehci_hcd *ehci)
|
||||
struct ehci_qh *qh;
|
||||
enum ehci_timer_action action = TIMER_IO_WATCHDOG;
|
||||
|
||||
ehci->stamp = ehci_readl(ehci, &ehci->regs->frame_index);
|
||||
timer_action_done (ehci, TIMER_ASYNC_SHRINK);
|
||||
rescan:
|
||||
stopped = !HC_IS_RUNNING(ehci_to_hcd(ehci)->state);
|
||||
qh = ehci->async->qh_next.qh;
|
||||
if (likely (qh != NULL)) {
|
||||
do {
|
||||
/* clean any finished work for this qh */
|
||||
if (!list_empty(&qh->qtd_list) && (stopped ||
|
||||
qh->stamp != ehci->stamp)) {
|
||||
int temp;
|
||||
|
||||
/* unlinks could happen here; completion
|
||||
* reporting drops the lock. rescan using
|
||||
* the latest schedule, but don't rescan
|
||||
* qhs we already finished (no looping)
|
||||
* unless the controller is stopped.
|
||||
*/
|
||||
qh = qh_get (qh);
|
||||
qh->stamp = ehci->stamp;
|
||||
temp = qh_completions (ehci, qh);
|
||||
if (qh->needs_rescan)
|
||||
unlink_async(ehci, qh);
|
||||
qh_put (qh);
|
||||
if (temp != 0) {
|
||||
goto rescan;
|
||||
}
|
||||
}
|
||||
ehci->qh_scan_next = ehci->async->qh_next.qh;
|
||||
while (ehci->qh_scan_next) {
|
||||
qh = ehci->qh_scan_next;
|
||||
ehci->qh_scan_next = qh->qh_next.qh;
|
||||
rescan:
|
||||
/* clean any finished work for this qh */
|
||||
if (!list_empty(&qh->qtd_list)) {
|
||||
int temp;
|
||||
|
||||
/* unlink idle entries, reducing DMA usage as well
|
||||
* as HCD schedule-scanning costs. delay for any qh
|
||||
* we just scanned, there's a not-unusual case that it
|
||||
* doesn't stay idle for long.
|
||||
* (plus, avoids some kind of re-activation race.)
|
||||
/*
|
||||
* Unlinks could happen here; completion reporting
|
||||
* drops the lock. That's why ehci->qh_scan_next
|
||||
* always holds the next qh to scan; if the next qh
|
||||
* gets unlinked then ehci->qh_scan_next is adjusted
|
||||
* in start_unlink_async().
|
||||
*/
|
||||
if (list_empty(&qh->qtd_list)
|
||||
&& qh->qh_state == QH_STATE_LINKED) {
|
||||
if (!ehci->reclaim && (stopped ||
|
||||
((ehci->stamp - qh->stamp) & 0x1fff)
|
||||
>= EHCI_SHRINK_FRAMES * 8))
|
||||
start_unlink_async(ehci, qh);
|
||||
else
|
||||
action = TIMER_ASYNC_SHRINK;
|
||||
}
|
||||
qh = qh_get(qh);
|
||||
temp = qh_completions(ehci, qh);
|
||||
if (qh->needs_rescan)
|
||||
unlink_async(ehci, qh);
|
||||
qh->unlink_time = jiffies + EHCI_SHRINK_JIFFIES;
|
||||
qh_put(qh);
|
||||
if (temp != 0)
|
||||
goto rescan;
|
||||
}
|
||||
|
||||
qh = qh->qh_next.qh;
|
||||
} while (qh);
|
||||
/* unlink idle entries, reducing DMA usage as well
|
||||
* as HCD schedule-scanning costs. delay for any qh
|
||||
* we just scanned, there's a not-unusual case that it
|
||||
* doesn't stay idle for long.
|
||||
* (plus, avoids some kind of re-activation race.)
|
||||
*/
|
||||
if (list_empty(&qh->qtd_list)
|
||||
&& qh->qh_state == QH_STATE_LINKED) {
|
||||
if (!ehci->reclaim && (stopped ||
|
||||
time_after_eq(jiffies, qh->unlink_time)))
|
||||
start_unlink_async(ehci, qh);
|
||||
else
|
||||
action = TIMER_ASYNC_SHRINK;
|
||||
}
|
||||
}
|
||||
if (action == TIMER_ASYNC_SHRINK)
|
||||
timer_action (ehci, TIMER_ASYNC_SHRINK);
|
||||
|
@@ -62,7 +62,7 @@ stm_ehci_bus_resume(struct usb_hcd *hcd)
|
||||
|
||||
static const struct hc_driver ehci_stm_hc_driver = {
|
||||
.description = hcd_name,
|
||||
.product_desc = "st-ehci",
|
||||
.product_desc = "STMicroelectronics EHCI Host Controller",
|
||||
.hcd_priv_size = sizeof(struct ehci_hcd),
|
||||
|
||||
/*
|
||||
@@ -199,6 +199,7 @@ static struct platform_driver ehci_hcd_stm_driver = {
|
||||
.shutdown = usb_hcd_platform_shutdown,
|
||||
.driver = {
|
||||
.name = "stm-ehci",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -216,7 +217,7 @@ int stm_ehci_hcd_unregister(struct platform_device *dev)
|
||||
ret = ehci_hcd_stm_remove(dev);
|
||||
mutex_unlock(&stm_ehci_usb_mutex);
|
||||
if (ret)
|
||||
dgb_print("[STM][USB] Error on %s 0x%x\n", __func__, dev);
|
||||
dgb_print("[STM][USB] Error on %s %p\n", __func__, dev);
|
||||
return ret;
|
||||
|
||||
}
|
||||
@@ -230,7 +231,7 @@ int stm_ehci_hcd_register(struct platform_device *dev)
|
||||
ret = ehci_hcd_stm_probe(dev);
|
||||
mutex_unlock(&stm_ehci_usb_mutex);
|
||||
if (ret)
|
||||
dgb_print("[STM][USB] Error on %s 0x%x\n", __func__, dev);
|
||||
dgb_print("[STM][USB] Error on %s %p\n", __func__, dev);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(stm_ehci_hcd_register);
|
||||
|
@@ -74,6 +74,7 @@ struct ehci_hcd { /* one per controller */
|
||||
/* async schedule support */
|
||||
struct ehci_qh *async;
|
||||
struct ehci_qh *reclaim;
|
||||
struct ehci_qh *qh_scan_next;
|
||||
unsigned scanning : 1;
|
||||
|
||||
/* periodic schedule support */
|
||||
@@ -116,7 +117,6 @@ struct ehci_hcd { /* one per controller */
|
||||
struct timer_list iaa_watchdog;
|
||||
struct timer_list watchdog;
|
||||
unsigned long actions;
|
||||
unsigned stamp;
|
||||
unsigned random_frame;
|
||||
unsigned long next_statechange;
|
||||
ktime_t last_periodic_enable;
|
||||
@@ -336,6 +336,7 @@ struct ehci_qh {
|
||||
struct ehci_qh *reclaim; /* next to reclaim */
|
||||
|
||||
struct ehci_hcd *ehci;
|
||||
unsigned long unlink_time;
|
||||
|
||||
/*
|
||||
* Do NOT use atomic operations for QH refcounting. On some CPUs
|
||||
@@ -367,6 +368,7 @@ struct ehci_qh {
|
||||
#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 */
|
||||
};
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Freescale QUICC Engine USB Host Controller Driver
|
||||
*
|
||||
* Copyright (c) Freescale Semicondutor, Inc. 2006.
|
||||
* Copyright (c) Freescale Semicondutor, Inc. 2006, 2011.
|
||||
* Shlomi Gridish <gridish@freescale.com>
|
||||
* Jerry Huang <Chang-Ming.Huang@freescale.com>
|
||||
* Copyright (c) Logic Product Development, Inc. 2007
|
||||
@@ -810,9 +810,11 @@ void fhci_queue_urb(struct fhci_hcd *fhci, struct urb *urb)
|
||||
ed->dev_addr = usb_pipedevice(urb->pipe);
|
||||
ed->max_pkt_size = usb_maxpacket(urb->dev, urb->pipe,
|
||||
usb_pipeout(urb->pipe));
|
||||
/* setup stage */
|
||||
td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt++, FHCI_TA_SETUP,
|
||||
USB_TD_TOGGLE_DATA0, urb->setup_packet, 8, 0, 0, true);
|
||||
|
||||
/* data stage */
|
||||
if (data_len > 0) {
|
||||
td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt++,
|
||||
usb_pipeout(urb->pipe) ? FHCI_TA_OUT :
|
||||
@@ -820,9 +822,18 @@ void fhci_queue_urb(struct fhci_hcd *fhci, struct urb *urb)
|
||||
USB_TD_TOGGLE_DATA1, data, data_len, 0, 0,
|
||||
true);
|
||||
}
|
||||
td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt++,
|
||||
usb_pipeout(urb->pipe) ? FHCI_TA_IN : FHCI_TA_OUT,
|
||||
USB_TD_TOGGLE_DATA1, data, 0, 0, 0, true);
|
||||
|
||||
/* status stage */
|
||||
if (data_len > 0)
|
||||
td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt++,
|
||||
(usb_pipeout(urb->pipe) ? FHCI_TA_IN :
|
||||
FHCI_TA_OUT),
|
||||
USB_TD_TOGGLE_DATA1, data, 0, 0, 0, true);
|
||||
else
|
||||
td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt++,
|
||||
FHCI_TA_IN,
|
||||
USB_TD_TOGGLE_DATA1, data, 0, 0, 0, true);
|
||||
|
||||
urb_state = US_CTRL_SETUP;
|
||||
break;
|
||||
case FHCI_TF_ISO:
|
||||
|
@@ -71,20 +71,21 @@ static int stm_usb_boot(struct platform_device *pdev)
|
||||
void *wrapper_base = usb_data->ahb2stbus_wrapper_glue_base;
|
||||
void *protocol_base = usb_data->ahb2stbus_protocol_base;
|
||||
unsigned long reg, req_reg;
|
||||
unsigned long flags = pl_data->flags;
|
||||
|
||||
if (pl_data->flags &
|
||||
(STM_PLAT_USB_FLAGS_STRAP_8BIT |
|
||||
STM_PLAT_USB_FLAGS_STRAP_16BIT)) {
|
||||
|
||||
if (flags & (STM_PLAT_USB_FLAGS_STRAP_8BIT |
|
||||
STM_PLAT_USB_FLAGS_STRAP_16BIT)) {
|
||||
/* Set strap mode */
|
||||
reg = readl(wrapper_base + AHB2STBUS_STRAP_OFFSET);
|
||||
if (pl_data->flags & STM_PLAT_USB_FLAGS_STRAP_16BIT)
|
||||
if (flags & STM_PLAT_USB_FLAGS_STRAP_16BIT)
|
||||
reg |= AHB2STBUS_STRAP_16_BIT;
|
||||
else
|
||||
reg &= ~AHB2STBUS_STRAP_16_BIT;
|
||||
writel(reg, wrapper_base + AHB2STBUS_STRAP_OFFSET);
|
||||
}
|
||||
|
||||
if (pl_data->flags & STM_PLAT_USB_FLAGS_STRAP_PLL) {
|
||||
if (flags & STM_PLAT_USB_FLAGS_STRAP_PLL) {
|
||||
/* Start PLL */
|
||||
reg = readl(wrapper_base + AHB2STBUS_STRAP_OFFSET);
|
||||
writel(reg | AHB2STBUS_STRAP_PLL,
|
||||
@@ -95,7 +96,7 @@ static int stm_usb_boot(struct platform_device *pdev)
|
||||
mdelay(30);
|
||||
}
|
||||
|
||||
if (pl_data->flags & STM_PLAT_USB_FLAGS_OPC_MSGSIZE_CHUNKSIZE) {
|
||||
if (flags & STM_PLAT_USB_FLAGS_OPC_MSGSIZE_CHUNKSIZE) {
|
||||
/* Set the STBus Opcode Config for load/store 32 */
|
||||
writel(AHB2STBUS_STBUS_OPC_32BIT,
|
||||
protocol_base + AHB2STBUS_STBUS_OPC_OFFSET);
|
||||
@@ -109,7 +110,7 @@ static int stm_usb_boot(struct platform_device *pdev)
|
||||
protocol_base + AHB2STBUS_CHUNKSIZE_OFFSET);
|
||||
}
|
||||
|
||||
if (pl_data->flags &
|
||||
if (flags &
|
||||
(STM_PLAT_USB_FLAGS_STBUS_CONFIG_THRESHOLD128 |
|
||||
STM_PLAT_USB_FLAGS_STBUS_CONFIG_THRESHOLD256)) {
|
||||
|
||||
@@ -134,24 +135,14 @@ static int stm_usb_boot(struct platform_device *pdev)
|
||||
|
||||
static int stm_usb_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct drv_usb_data *dr_data = platform_get_drvdata(pdev);
|
||||
|
||||
platform_device_unregister(dr_data->ehci_device);
|
||||
platform_device_unregister(dr_data->ohci_device);
|
||||
|
||||
stm_device_power(dr_data->device_state, stm_device_power_off);
|
||||
|
||||
stm_usb_clk_disable(dr_data);
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "wrapper");
|
||||
devm_release_mem_region(dev, res->start, resource_size(res));
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "protocol");
|
||||
devm_release_mem_region(dev, res->start, resource_size(res));
|
||||
|
||||
if (dr_data->ehci_device)
|
||||
platform_device_unregister(dr_data->ehci_device);
|
||||
if (dr_data->ohci_device)
|
||||
platform_device_unregister(dr_data->ohci_device);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -191,7 +182,7 @@ static int __init stm_usb_probe(struct platform_device *pdev)
|
||||
struct drv_usb_data *dr_data;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct resource *res;
|
||||
int ret = 0, i;
|
||||
int i;
|
||||
static char __initdata *usb_clks_n[USB_CLKS_NR] = {
|
||||
[USB_48_CLK] = "usb_48_clk",
|
||||
[USB_IC_CLK] = "usb_ic_clk",
|
||||
@@ -200,7 +191,7 @@ static int __init stm_usb_probe(struct platform_device *pdev)
|
||||
resource_size_t len;
|
||||
|
||||
dgb_print("\n");
|
||||
dr_data = kzalloc(sizeof(struct drv_usb_data), GFP_KERNEL);
|
||||
dr_data = devm_kzalloc(dev, sizeof(*dr_data), GFP_KERNEL);
|
||||
if (!dr_data)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -215,57 +206,47 @@ static int __init stm_usb_probe(struct platform_device *pdev)
|
||||
|
||||
stm_usb_clk_enable(dr_data);
|
||||
|
||||
dr_data->device_state = devm_stm_device_init(&pdev->dev,
|
||||
plat_data->device_config);
|
||||
if (!dr_data->device_state) {
|
||||
ret = -EBUSY;
|
||||
goto err_0;
|
||||
}
|
||||
dr_data->device_state =
|
||||
devm_stm_device_init(&pdev->dev, plat_data->device_config);
|
||||
if (!dr_data->device_state)
|
||||
return -EBUSY;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "wrapper");
|
||||
if (!res) {
|
||||
ret = -ENXIO;
|
||||
goto err_0;
|
||||
}
|
||||
if (!res)
|
||||
return -ENXIO;
|
||||
|
||||
len = resource_size(res);
|
||||
if (devm_request_mem_region(dev, res->start, len, pdev->name) < 0) {
|
||||
ret = -EBUSY;
|
||||
goto err_0;
|
||||
}
|
||||
if (devm_request_mem_region(dev, res->start, len, pdev->name) < 0)
|
||||
return -EBUSY;
|
||||
|
||||
dr_data->ahb2stbus_wrapper_glue_base =
|
||||
devm_ioremap_nocache(dev, res->start, len);
|
||||
|
||||
if (!dr_data->ahb2stbus_wrapper_glue_base) {
|
||||
ret = -EFAULT;
|
||||
goto err_1;
|
||||
}
|
||||
if (!dr_data->ahb2stbus_wrapper_glue_base)
|
||||
return -EFAULT;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "protocol");
|
||||
if (!res) {
|
||||
ret = -ENXIO;
|
||||
goto err_2;
|
||||
}
|
||||
if (!res)
|
||||
return -ENXIO;
|
||||
|
||||
len = resource_size(res);
|
||||
if (devm_request_mem_region(dev, res->start, len, pdev->name) < 0) {
|
||||
ret = -EBUSY;
|
||||
goto err_2;
|
||||
}
|
||||
if (devm_request_mem_region(dev, res->start, len, pdev->name) < 0)
|
||||
return -EBUSY;
|
||||
|
||||
dr_data->ahb2stbus_protocol_base =
|
||||
devm_ioremap_nocache(dev, res->start, len);
|
||||
|
||||
if (!dr_data->ahb2stbus_protocol_base) {
|
||||
ret = -EFAULT;
|
||||
goto err_3;
|
||||
}
|
||||
if (!dr_data->ahb2stbus_protocol_base)
|
||||
return -EFAULT;
|
||||
|
||||
stm_usb_boot(pdev);
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ehci");
|
||||
if (res) {
|
||||
dr_data->ehci_device = stm_usb_device_create("stm-ehci",
|
||||
pdev->id, pdev);
|
||||
if (IS_ERR(dr_data->ehci_device)) {
|
||||
ret = (int)dr_data->ehci_device;
|
||||
goto err_4;
|
||||
}
|
||||
if (IS_ERR(dr_data->ehci_device))
|
||||
return PTR_ERR(dr_data->ehci_device);
|
||||
}
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ohci");
|
||||
@@ -273,10 +254,8 @@ static int __init stm_usb_probe(struct platform_device *pdev)
|
||||
dr_data->ohci_device =
|
||||
stm_usb_device_create("stm-ohci", pdev->id, pdev);
|
||||
if (IS_ERR(dr_data->ohci_device)) {
|
||||
if (dr_data->ehci_device)
|
||||
platform_device_del(dr_data->ehci_device);
|
||||
ret = (int)dr_data->ohci_device;
|
||||
goto err_4;
|
||||
platform_device_del(dr_data->ehci_device);
|
||||
return PTR_ERR(dr_data->ohci_device);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -285,21 +264,7 @@ static int __init stm_usb_probe(struct platform_device *pdev)
|
||||
pm_suspend_ignore_children(&pdev->dev, 1);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
return ret;
|
||||
|
||||
err_4:
|
||||
devm_iounmap(dev, dr_data->ahb2stbus_protocol_base);
|
||||
err_3:
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "protocol");
|
||||
devm_release_mem_region(dev, res->start, resource_size(res));
|
||||
err_2:
|
||||
devm_iounmap(dev, dr_data->ahb2stbus_wrapper_glue_base);
|
||||
err_1:
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "wrapper");
|
||||
devm_release_mem_region(dev, res->start, resource_size(res));
|
||||
err_0:
|
||||
kfree(dr_data);
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void stm_usb_shutdown(struct platform_device *pdev)
|
||||
|
@@ -56,7 +56,7 @@ static int stm_ohci_bus_suspend(struct usb_hcd *hcd)
|
||||
|
||||
static const struct hc_driver ohci_st40_hc_driver = {
|
||||
.description = hcd_name,
|
||||
.product_desc = "stm-ohci",
|
||||
.product_desc = "STMicroelectronics OHCI Host Controller",
|
||||
.hcd_priv_size = sizeof(struct ohci_hcd),
|
||||
|
||||
/* generic hardware linkage */
|
||||
@@ -165,6 +165,7 @@ static struct platform_driver ohci_hcd_stm_driver = {
|
||||
.shutdown = usb_hcd_platform_shutdown,
|
||||
.driver = {
|
||||
.name = "stm-ohci",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -183,7 +184,7 @@ int stm_ohci_hcd_unregister(struct platform_device *dev)
|
||||
ret = ohci_hcd_stm_remove(dev);
|
||||
mutex_unlock(&stm_ohci_usb_mutex);
|
||||
if (ret)
|
||||
dgb_print("[STM][USB] Error on %s 0x%x\n", __func__, dev);
|
||||
dgb_print("[STM][USB] Error on %s %p\n", __func__, dev);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(stm_ohci_hcd_unregister);
|
||||
@@ -196,7 +197,7 @@ int stm_ohci_hcd_register(struct platform_device *dev)
|
||||
ret = ohci_hcd_stm_probe(dev);
|
||||
mutex_unlock(&stm_ohci_usb_mutex);
|
||||
if (ret)
|
||||
dgb_print("[STM][USB] Error on %s 0x%x\n", __func__, dev);
|
||||
dgb_print("[STM][USB] Error on %s %p\n", __func__, dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@@ -34,6 +34,8 @@
|
||||
#define OHCI_INTRSTATUS 0x0c
|
||||
#define OHCI_INTRENABLE 0x10
|
||||
#define OHCI_INTRDISABLE 0x14
|
||||
#define OHCI_FMINTERVAL 0x34
|
||||
#define OHCI_HCR (1 << 0) /* host controller reset */
|
||||
#define OHCI_OCR (1 << 3) /* ownership change request */
|
||||
#define OHCI_CTRL_RWC (1 << 9) /* remote wakeup connected */
|
||||
#define OHCI_CTRL_IR (1 << 8) /* interrupt routing */
|
||||
@@ -204,6 +206,32 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev)
|
||||
|
||||
/* reset controller, preserving RWC (and possibly IR) */
|
||||
writel(control & OHCI_CTRL_MASK, base + OHCI_CONTROL);
|
||||
readl(base + OHCI_CONTROL);
|
||||
|
||||
/* Some NVIDIA controllers stop working if kept in RESET for too long */
|
||||
if (pdev->vendor == PCI_VENDOR_ID_NVIDIA) {
|
||||
u32 fminterval;
|
||||
int cnt;
|
||||
|
||||
/* drive reset for at least 50 ms (7.1.7.5) */
|
||||
msleep(50);
|
||||
|
||||
/* software reset of the controller, preserving HcFmInterval */
|
||||
fminterval = readl(base + OHCI_FMINTERVAL);
|
||||
writel(OHCI_HCR, base + OHCI_CMDSTATUS);
|
||||
|
||||
/* reset requires max 10 us delay */
|
||||
for (cnt = 30; cnt > 0; --cnt) { /* ... allow extra time */
|
||||
if ((readl(base + OHCI_CMDSTATUS) & OHCI_HCR) == 0)
|
||||
break;
|
||||
udelay(1);
|
||||
}
|
||||
writel(fminterval, base + OHCI_FMINTERVAL);
|
||||
|
||||
/* Now we're in the SUSPEND state with all devices reset
|
||||
* and wakeups and interrupts disabled
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
* disable interrupts
|
||||
@@ -390,12 +418,12 @@ static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev)
|
||||
void __iomem *op_reg_base;
|
||||
u32 val;
|
||||
int timeout;
|
||||
int len = pci_resource_len(pdev, 0);
|
||||
|
||||
if (!mmio_resource_enabled(pdev, 0))
|
||||
return;
|
||||
|
||||
base = ioremap_nocache(pci_resource_start(pdev, 0),
|
||||
pci_resource_len(pdev, 0));
|
||||
base = ioremap_nocache(pci_resource_start(pdev, 0), len);
|
||||
if (base == NULL)
|
||||
return;
|
||||
|
||||
@@ -405,9 +433,17 @@ static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev)
|
||||
*/
|
||||
ext_cap_offset = xhci_find_next_cap_offset(base, XHCI_HCC_PARAMS_OFFSET);
|
||||
do {
|
||||
if ((ext_cap_offset + sizeof(val)) > len) {
|
||||
/* We're reading garbage from the controller */
|
||||
dev_warn(&pdev->dev,
|
||||
"xHCI controller failing to respond");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ext_cap_offset)
|
||||
/* We've reached the end of the extended capabilities */
|
||||
goto hc_init;
|
||||
|
||||
val = readl(base + ext_cap_offset);
|
||||
if (XHCI_EXT_CAPS_ID(val) == XHCI_EXT_CAPS_LEGACY)
|
||||
break;
|
||||
@@ -416,7 +452,7 @@ static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev)
|
||||
|
||||
/* If the BIOS owns the HC, signal that the OS wants it, and wait */
|
||||
if (val & XHCI_HC_BIOS_OWNED) {
|
||||
writel(val & XHCI_HC_OS_OWNED, base + ext_cap_offset);
|
||||
writel(val | XHCI_HC_OS_OWNED, base + ext_cap_offset);
|
||||
|
||||
/* Wait for 5 seconds with 10 microsecond polling interval */
|
||||
timeout = handshake(base + ext_cap_offset, XHCI_HC_BIOS_OWNED,
|
||||
@@ -430,9 +466,13 @@ static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev)
|
||||
}
|
||||
}
|
||||
|
||||
/* Disable any BIOS SMIs */
|
||||
writel(XHCI_LEGACY_DISABLE_SMI,
|
||||
base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET);
|
||||
val = readl(base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET);
|
||||
/* Mask off (turn off) any enabled SMIs */
|
||||
val &= XHCI_LEGACY_DISABLE_SMI;
|
||||
/* Mask all SMI events bits, RW1C */
|
||||
val |= XHCI_LEGACY_SMI_EVENTS;
|
||||
/* Disable any BIOS SMIs and clear all SMI events*/
|
||||
writel(val, base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET);
|
||||
|
||||
hc_init:
|
||||
op_reg_base = base + XHCI_HC_LENGTH(readl(base));
|
||||
@@ -470,6 +510,22 @@ hc_init:
|
||||
|
||||
static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev)
|
||||
{
|
||||
/* Skip Netlogic mips SoC's internal PCI USB controller.
|
||||
* This device does not need/support EHCI/OHCI handoff
|
||||
*/
|
||||
if (pdev->vendor == 0x184e) /* vendor Netlogic */
|
||||
return;
|
||||
if (pdev->class != PCI_CLASS_SERIAL_USB_UHCI &&
|
||||
pdev->class != PCI_CLASS_SERIAL_USB_OHCI &&
|
||||
pdev->class != PCI_CLASS_SERIAL_USB_EHCI &&
|
||||
pdev->class != PCI_CLASS_SERIAL_USB_XHCI)
|
||||
return;
|
||||
|
||||
if (pci_enable_device(pdev) < 0) {
|
||||
dev_warn(&pdev->dev, "Can't enable PCI device, "
|
||||
"BIOS handoff failed.\n");
|
||||
return;
|
||||
}
|
||||
if (pdev->class == PCI_CLASS_SERIAL_USB_UHCI)
|
||||
quirk_usb_handoff_uhci(pdev);
|
||||
else if (pdev->class == PCI_CLASS_SERIAL_USB_OHCI)
|
||||
@@ -478,5 +534,6 @@ static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev)
|
||||
quirk_usb_disable_ehci(pdev);
|
||||
else if (pdev->class == PCI_CLASS_SERIAL_USB_XHCI)
|
||||
quirk_usb_handoff_xhci(pdev);
|
||||
pci_disable_device(pdev);
|
||||
}
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_usb_early_handoff);
|
||||
|
@@ -104,7 +104,7 @@ void qset_clear(struct whc *whc, struct whc_qset *qset)
|
||||
{
|
||||
qset->td_start = qset->td_end = qset->ntds = 0;
|
||||
|
||||
qset->qh.link = cpu_to_le32(QH_LINK_NTDS(8) | QH_LINK_T);
|
||||
qset->qh.link = cpu_to_le64(QH_LINK_NTDS(8) | QH_LINK_T);
|
||||
qset->qh.status = qset->qh.status & QH_STATUS_SEQ_MASK;
|
||||
qset->qh.err_count = 0;
|
||||
qset->qh.scratch[0] = 0;
|
||||
|
@@ -62,8 +62,9 @@
|
||||
/* 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:2, 5:12, and 17:19 need to be preserved; bits 21:28 should be zero */
|
||||
#define XHCI_LEGACY_DISABLE_SMI ((0x3 << 1) + (0xff << 5) + (0x7 << 17))
|
||||
/* 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)
|
||||
|
||||
/* command register values to disable interrupts and halt the HC */
|
||||
/* start/stop HC execution - do not write unless HC is halted*/
|
||||
|
@@ -150,7 +150,7 @@ int xhci_reset(struct xhci_hcd *xhci)
|
||||
xhci_to_hcd(xhci)->state = HC_STATE_HALT;
|
||||
|
||||
ret = handshake(xhci, &xhci->op_regs->command,
|
||||
CMD_RESET, 0, 250 * 1000);
|
||||
CMD_RESET, 0, 10 * 1000 * 1000);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -979,6 +979,7 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
|
||||
u32 added_ctxs;
|
||||
unsigned int last_ctx;
|
||||
u32 new_add_flags, new_drop_flags, new_slot_info;
|
||||
struct xhci_virt_device *virt_dev;
|
||||
int ret = 0;
|
||||
|
||||
ret = xhci_check_args(hcd, udev, ep, 1, __func__);
|
||||
@@ -1007,11 +1008,25 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
in_ctx = xhci->devs[udev->slot_id]->in_ctx;
|
||||
out_ctx = xhci->devs[udev->slot_id]->out_ctx;
|
||||
virt_dev = xhci->devs[udev->slot_id];
|
||||
in_ctx = virt_dev->in_ctx;
|
||||
out_ctx = virt_dev->out_ctx;
|
||||
ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx);
|
||||
ep_index = xhci_get_endpoint_index(&ep->desc);
|
||||
ep_ctx = xhci_get_ep_ctx(xhci, out_ctx, ep_index);
|
||||
|
||||
/* If this endpoint is already in use, and the upper layers are trying
|
||||
* to add it again without dropping it, reject the addition.
|
||||
*/
|
||||
if (virt_dev->eps[ep_index].ring &&
|
||||
!(le32_to_cpu(ctrl_ctx->drop_flags) &
|
||||
xhci_get_endpoint_flag(&ep->desc))) {
|
||||
xhci_warn(xhci, "Trying to add endpoint 0x%x "
|
||||
"without dropping it.\n",
|
||||
(unsigned int) ep->desc.bEndpointAddress);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* If the HCD has already noted the endpoint is enabled,
|
||||
* ignore this request.
|
||||
*/
|
||||
@@ -1026,8 +1041,7 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
|
||||
* process context, not interrupt context (or so documenation
|
||||
* for usb_set_interface() and usb_set_configuration() claim).
|
||||
*/
|
||||
if (xhci_endpoint_init(xhci, xhci->devs[udev->slot_id],
|
||||
udev, ep, GFP_KERNEL) < 0) {
|
||||
if (xhci_endpoint_init(xhci, virt_dev, udev, ep, GFP_NOIO) < 0) {
|
||||
dev_dbg(&udev->dev, "%s - could not initialize ep %#x\n",
|
||||
__func__, ep->desc.bEndpointAddress);
|
||||
return -ENOMEM;
|
||||
|
@@ -110,18 +110,20 @@ void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring)
|
||||
struct xhci_segment *seg;
|
||||
struct xhci_segment *first_seg;
|
||||
|
||||
if (!ring || !ring->first_seg)
|
||||
if (!ring)
|
||||
return;
|
||||
first_seg = ring->first_seg;
|
||||
seg = first_seg->next;
|
||||
xhci_dbg(xhci, "Freeing ring at %p\n", ring);
|
||||
while (seg != first_seg) {
|
||||
struct xhci_segment *next = seg->next;
|
||||
xhci_segment_free(xhci, seg);
|
||||
seg = next;
|
||||
if (ring->first_seg) {
|
||||
first_seg = ring->first_seg;
|
||||
seg = first_seg->next;
|
||||
xhci_dbg(xhci, "Freeing ring at %p\n", ring);
|
||||
while (seg != first_seg) {
|
||||
struct xhci_segment *next = seg->next;
|
||||
xhci_segment_free(xhci, seg);
|
||||
seg = next;
|
||||
}
|
||||
xhci_segment_free(xhci, first_seg);
|
||||
ring->first_seg = NULL;
|
||||
}
|
||||
xhci_segment_free(xhci, first_seg);
|
||||
ring->first_seg = NULL;
|
||||
kfree(ring);
|
||||
}
|
||||
|
||||
@@ -470,26 +472,42 @@ static unsigned int xhci_parse_exponent_interval(struct usb_device *udev,
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert bInterval expressed in frames (in 1-255 range) to exponent of
|
||||
* Convert bInterval expressed in microframes (in 1-255 range) to exponent of
|
||||
* microframes, rounded down to nearest power of 2.
|
||||
*/
|
||||
static unsigned int xhci_parse_frame_interval(struct usb_device *udev,
|
||||
struct usb_host_endpoint *ep)
|
||||
static unsigned int xhci_microframes_to_exponent(struct usb_device *udev,
|
||||
struct usb_host_endpoint *ep, unsigned int desc_interval,
|
||||
unsigned int min_exponent, unsigned int max_exponent)
|
||||
{
|
||||
unsigned int interval;
|
||||
|
||||
interval = fls(8 * ep->desc.bInterval) - 1;
|
||||
interval = clamp_val(interval, 3, 10);
|
||||
if ((1 << interval) != 8 * ep->desc.bInterval)
|
||||
interval = fls(desc_interval) - 1;
|
||||
interval = clamp_val(interval, min_exponent, max_exponent);
|
||||
if ((1 << interval) != desc_interval)
|
||||
dev_warn(&udev->dev,
|
||||
"ep %#x - rounding interval to %d microframes, ep desc says %d microframes\n",
|
||||
ep->desc.bEndpointAddress,
|
||||
1 << interval,
|
||||
8 * ep->desc.bInterval);
|
||||
desc_interval);
|
||||
|
||||
return interval;
|
||||
}
|
||||
|
||||
static unsigned int xhci_parse_microframe_interval(struct usb_device *udev,
|
||||
struct usb_host_endpoint *ep)
|
||||
{
|
||||
return xhci_microframes_to_exponent(udev, ep,
|
||||
ep->desc.bInterval, 0, 15);
|
||||
}
|
||||
|
||||
|
||||
static unsigned int xhci_parse_frame_interval(struct usb_device *udev,
|
||||
struct usb_host_endpoint *ep)
|
||||
{
|
||||
return xhci_microframes_to_exponent(udev, ep,
|
||||
ep->desc.bInterval * 8, 3, 10);
|
||||
}
|
||||
|
||||
/* Return the polling or NAK interval.
|
||||
*
|
||||
* The polling interval is expressed in "microframes". If xHCI's Interval field
|
||||
@@ -508,7 +526,7 @@ static inline unsigned int xhci_get_endpoint_interval(struct usb_device *udev,
|
||||
/* Max NAK rate */
|
||||
if (usb_endpoint_xfer_control(&ep->desc) ||
|
||||
usb_endpoint_xfer_bulk(&ep->desc)) {
|
||||
interval = ep->desc.bInterval;
|
||||
interval = xhci_parse_microframe_interval(udev, ep);
|
||||
break;
|
||||
}
|
||||
/* Fall through - SS and HS isoc/int have same decoding */
|
||||
@@ -916,11 +934,6 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
|
||||
int i;
|
||||
|
||||
/* Free the Event Ring Segment Table and the actual Event Ring */
|
||||
if (xhci->ir_set) {
|
||||
xhci_writel(xhci, 0, &xhci->ir_set->erst_size);
|
||||
xhci_write_64(xhci, 0, &xhci->ir_set->erst_base);
|
||||
xhci_write_64(xhci, 0, &xhci->ir_set->erst_dequeue);
|
||||
}
|
||||
size = sizeof(struct xhci_erst_entry)*(xhci->erst.num_entries);
|
||||
if (xhci->erst.entries)
|
||||
pci_free_consistent(pdev, size,
|
||||
@@ -932,7 +945,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
|
||||
xhci->event_ring = NULL;
|
||||
xhci_dbg(xhci, "Freed event ring\n");
|
||||
|
||||
xhci_write_64(xhci, 0, &xhci->op_regs->cmd_ring);
|
||||
xhci->cmd_ring_reserved_trbs = 0;
|
||||
if (xhci->cmd_ring)
|
||||
xhci_ring_free(xhci, xhci->cmd_ring);
|
||||
xhci->cmd_ring = NULL;
|
||||
@@ -951,7 +964,6 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
|
||||
xhci->device_pool = NULL;
|
||||
xhci_dbg(xhci, "Freed device context pool\n");
|
||||
|
||||
xhci_write_64(xhci, 0, &xhci->op_regs->dcbaa_ptr);
|
||||
if (xhci->dcbaa)
|
||||
pci_free_consistent(pdev, sizeof(*xhci->dcbaa),
|
||||
xhci->dcbaa, xhci->dcbaa->dma);
|
||||
@@ -1128,6 +1140,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
|
||||
|
||||
fail:
|
||||
xhci_warn(xhci, "Couldn't initialize memory\n");
|
||||
xhci_halt(xhci);
|
||||
xhci_reset(xhci);
|
||||
xhci_mem_cleanup(xhci);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
Reference in New Issue
Block a user