GitLab has been upgraded to 13.3.6. If you encounter any issues mail code@riscosopen.org

Commit a17ef0c8 authored by Jeffrey Lee's avatar Jeffrey Lee

Update to latest code from Raspberry Pi github

Detail:
  Makefile, dwc/* - Updated to latest code from Raspberry Pi github (rev e0001dd59d). Includes the fabled 'FIQ fix' code, although the code isn't yet enabled in the RISC OS version of the driver.
  c/cmodule - Add extra flags for controlling driver behaviour, as required by the new core code
  c/dwc_otg_riscos - Add some missing driver parameters (although we leave them at default). Handle DWC_E_SHUTDOWN xfer errors, which will now be produced when the driver is shutting down
  c/softc_device - Disable interrupts around dwc_otg_hcd_urb_enqueue, to mirror behaviour of Linux code (previously, it was the responsibility of the DWC code to disable interrupts for the appropriate part of the operation)
  s/regaccess - Add some extra IRQ/memory barrier functions required by the new code (mainly the FIQ fix). Make DWC_MODIFY_REG32 operate atomicly (mirrors change in Linux version)
Admin:
  Tested on Raspberry Pi


Version 0.11. Tagged as 'DWCDriver-0_11'
parent 07e72b27
......@@ -47,6 +47,7 @@ VPATH = ^.^.build ^.^.dev.usb dwc.driver dwc.dwc_common_port
# DWC bits
CFLAGS += -DDWC_EN_ISOC -Idwc.dwc_common_port -DDWC_HOST_ONLY
CFLAGS += -Dnotrace=
OBJS += dwc_otg_cil dwc_otg_cil_intr dwc_otg_hcd dwc_otg_hcd_intr dwc_otg_hcd_queue dwc_otg_hcd_ddma dwc_otg_adp
# OBJS += dwc_cc dwc_modpow dwc_notifier dwc_mem
......
/* (0.10)
/* (0.11)
*
* This file is automatically maintained by srccommit, do not edit manually.
* Last processed by srccommit version: 1.1.
*
*/
#define Module_MajorVersion_CMHG 0.10
#define Module_MajorVersion_CMHG 0.11
#define Module_MinorVersion_CMHG
#define Module_Date_CMHG 30 Mar 2013
#define Module_Date_CMHG 26 Apr 2014
#define Module_MajorVersion "0.10"
#define Module_Version 10
#define Module_MajorVersion "0.11"
#define Module_Version 11
#define Module_MinorVersion ""
#define Module_Date "30 Mar 2013"
#define Module_Date "26 Apr 2014"
#define Module_ApplicationDate "30-Mar-13"
#define Module_ApplicationDate "26-Apr-14"
#define Module_ComponentName "DWCDriver"
#define Module_ComponentPath "mixed/RiscOS/Sources/HWSupport/USB/Controllers/DWCDriver"
#define Module_FullVersion "0.10"
#define Module_HelpVersion "0.10 (30 Mar 2013)"
#define Module_LibraryVersionInfo "0:10"
#define Module_FullVersion "0.11"
#define Module_HelpVersion "0.11 (26 Apr 2014)"
#define Module_LibraryVersionInfo "0:11"
......@@ -81,6 +81,9 @@ int dwcdebug; /* Debug level */
#endif
bool microframe_schedule = true;
bool nak_holdoff_enable = true;
bool fiq_fix_enable = false;
bool fiq_split_enable = false;
extern int * init_veneer (void);
......
......@@ -91,6 +91,13 @@ struct dwc_otg_driver_module_params {
int32_t lpm_enable;
int32_t ic_usb_cap;
int32_t ahb_thr_ratio;
int32_t power_down;
int32_t reload_ctl;
int32_t dev_out_nak;
int32_t cont_on_bna;
int32_t ahb_single;
int32_t otg_ver;
int32_t adp_enable;
};
/*
......@@ -372,6 +379,9 @@ static int hcd_op_complete(dwc_otg_hcd_t *hcd,void *urb_handle,dwc_otg_hcd_urb_t
case -DWC_E_OVERFLOW:
ex->xfer.status = USBD_IOERROR;
break;
case -DWC_E_SHUTDOWN:
ex->xfer.status = USBD_CANCELLED;
break;
case 0:
ex->xfer.status = USBD_NORMAL_COMPLETION;
break;
......@@ -490,7 +500,7 @@ _kernel_oserror *dwc_otg_riscos_init(const uint32_t *hw_base,int device_number,d
/* DWCTODO - params should come from HAL */
struct dwc_otg_driver_module_params s_params;
memset(&s_params,-1,sizeof(s_params));
s_params.lpm_enable = 0; /* Specified via kernel boot args in R-Pi linux */
s_params.lpm_enable = 0; /* From dwc_otg_driver.c */
struct dwc_otg_driver_module_params *params = &s_params;
......@@ -543,6 +553,13 @@ _kernel_oserror *dwc_otg_riscos_init(const uint32_t *hw_base,int device_number,d
SETPARAM(tx_thr_length)
SETPARAM(rx_thr_length)
SETPARAM(ahb_thr_ratio)
SETPARAM(power_down)
SETPARAM(reload_ctl)
SETPARAM(dev_out_nak)
SETPARAM(cont_on_bna)
SETPARAM(ahb_single)
SETPARAM(otg_ver)
SETPARAM(adp_enable)
if(ret)
{
......
......@@ -132,6 +132,9 @@ usbd_status softc_device_start(usbd_xfer_handle xfer)
bool timeout = ex->xfer.timeout && !sc->sc_bus.use_polling;
dwc_irqflags_t irqflags;
DWC_SPINLOCK_IRQSAVE(sc->dwc_dev.hcd->lock, &irqflags);
if(timeout) {
DPRINTFN(10,("-> set timeout %d on %x\n",ex->xfer.timeout,ex));
callout_reset(&(ex->xfer.timeout_handle), (MS_TO_TICKS(ex->xfer.timeout)), (softc_device_timeout), (ex));
......@@ -147,6 +150,8 @@ usbd_status softc_device_start(usbd_xfer_handle xfer)
}
}
DWC_SPINUNLOCK_IRQRESTORE(sc->dwc_dev.hcd->lock, irqflags);
switch(ret)
{
......
......@@ -909,7 +909,7 @@ static ssize_t regdump_show(struct device *_dev,
return sprintf(buf, "Register Dump\n");
}
DEVICE_ATTR(regdump, S_IRUGO | S_IWUSR, regdump_show, 0);
DEVICE_ATTR(regdump, S_IRUGO, regdump_show, 0);
/**
* Dump global registers and either host or device registers (depending on the
......@@ -920,12 +920,12 @@ static ssize_t spramdump_show(struct device *_dev,
{
dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
dwc_otg_dump_spram(otg_dev->core_if);
//dwc_otg_dump_spram(otg_dev->core_if);
return sprintf(buf, "SPRAM Dump\n");
}
DEVICE_ATTR(spramdump, S_IRUGO | S_IWUSR, spramdump_show, 0);
DEVICE_ATTR(spramdump, S_IRUGO, spramdump_show, 0);
/**
* Dump the current hcd state.
......@@ -940,7 +940,7 @@ static ssize_t hcddump_show(struct device *_dev,
return sprintf(buf, "HCD Dump\n");
}
DEVICE_ATTR(hcddump, S_IRUGO | S_IWUSR, hcddump_show, 0);
DEVICE_ATTR(hcddump, S_IRUGO, hcddump_show, 0);
/**
* Dump the average frame remaining at SOF. This can be used to
......@@ -958,7 +958,7 @@ static ssize_t hcd_frrem_show(struct device *_dev,
return sprintf(buf, "HCD Dump Frame Remaining\n");
}
DEVICE_ATTR(hcd_frrem, S_IRUGO | S_IWUSR, hcd_frrem_show, 0);
DEVICE_ATTR(hcd_frrem, S_IRUGO, hcd_frrem_show, 0);
/**
* Displays the time required to read the GNPTXFSIZ register many times (the
......@@ -986,7 +986,7 @@ static ssize_t rd_reg_test_show(struct device *_dev,
RW_REG_COUNT, time * MSEC_PER_JIFFIE, time);
}
DEVICE_ATTR(rd_reg_test, S_IRUGO | S_IWUSR, rd_reg_test_show, 0);
DEVICE_ATTR(rd_reg_test, S_IRUGO, rd_reg_test_show, 0);
/**
* Displays the time required to write the GNPTXFSIZ register many times (the
......@@ -1014,7 +1014,7 @@ static ssize_t wr_reg_test_show(struct device *_dev,
RW_REG_COUNT, time * MSEC_PER_JIFFIE, time);
}
DEVICE_ATTR(wr_reg_test, S_IRUGO | S_IWUSR, wr_reg_test_show, 0);
DEVICE_ATTR(wr_reg_test, S_IRUGO, wr_reg_test_show, 0);
#ifdef CONFIG_USB_DWC_OTG_LPM
......
......@@ -45,6 +45,7 @@
#include "dwc_otg_driver.h"
#include "dwc_otg_pcd.h"
#include "dwc_otg_hcd.h"
#include "dwc_otg_mphi_fix.h"
#ifdef DEBUG
static inline const char *op_state_str(dwc_otg_core_if_t * core_if)
......@@ -1318,7 +1319,7 @@ static int32_t dwc_otg_handle_lpm_intr(dwc_otg_core_if_t * core_if)
/**
* This function returns the Core Interrupt register.
*/
static inline uint32_t dwc_otg_read_common_intr(dwc_otg_core_if_t * core_if)
static inline uint32_t dwc_otg_read_common_intr(dwc_otg_core_if_t * core_if, gintmsk_data_t *reenable_gintmsk)
{
gahbcfg_data_t gahbcfg = {.d32 = 0 };
gintsts_data_t gintsts;
......@@ -1335,26 +1336,45 @@ static inline uint32_t dwc_otg_read_common_intr(dwc_otg_core_if_t * core_if)
gintmsk_common.b.lpmtranrcvd = 1;
#endif
gintmsk_common.b.restoredone = 1;
/** @todo: The port interrupt occurs while in device
* mode. Added code to CIL to clear the interrupt for now!
*/
gintmsk_common.b.portintr = 1;
if(dwc_otg_is_device_mode(core_if))
{
/** @todo: The port interrupt occurs while in device
* mode. Added code to CIL to clear the interrupt for now!
*/
gintmsk_common.b.portintr = 1;
}
gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
gintmsk.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
{
unsigned long flags;
// Re-enable the saved interrupts
local_irq_save(flags);
local_fiq_disable();
gintmsk.d32 |= gintmsk_common.d32;
gintsts_saved.d32 &= ~gintmsk_common.d32;
reenable_gintmsk->d32 = gintmsk.d32;
local_irq_restore(flags);
}
gahbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gahbcfg);
#ifdef DEBUG
/* if any common interrupts set */
if (gintsts.d32 & gintmsk_common.d32) {
DWC_DEBUGPL(DBG_ANY, "gintsts=%08x gintmsk=%08x\n",
DWC_DEBUGPL(DBG_ANY, "common_intr: gintsts=%08x gintmsk=%08x\n",
gintsts.d32, gintmsk.d32);
}
#endif
if (gahbcfg.b.glblintrmsk)
if (!fiq_fix_enable){
if (gahbcfg.b.glblintrmsk)
return ((gintsts.d32 & gintmsk.d32) & gintmsk_common.d32);
else
return 0;
}
else {
return ((gintsts.d32 & gintmsk.d32) & gintmsk_common.d32);
else
return 0;
}
}
......@@ -1386,6 +1406,7 @@ int32_t dwc_otg_handle_common_intr(void *dev)
{
int retval = 0;
gintsts_data_t gintsts;
gintmsk_data_t reenable_gintmsk;
gpwrdn_data_t gpwrdn = {.d32 = 0 };
dwc_otg_device_t *otg_dev = dev;
dwc_otg_core_if_t *core_if = otg_dev->core_if;
......@@ -1407,7 +1428,7 @@ int32_t dwc_otg_handle_common_intr(void *dev)
}
if (core_if->hibernation_suspend <= 0) {
gintsts.d32 = dwc_otg_read_common_intr(core_if);
gintsts.d32 = dwc_otg_read_common_intr(core_if, &reenable_gintmsk);
if (gintsts.b.modemismatch) {
retval |= dwc_otg_handle_mode_mismatch_intr(core_if);
......@@ -1504,8 +1525,12 @@ int32_t dwc_otg_handle_common_intr(void *dev)
gintsts.b.portintr = 1;
DWC_WRITE_REG32(&core_if->core_global_regs->gintsts,gintsts.d32);
retval |= 1;
reenable_gintmsk.b.portintr = 1;
}
DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, reenable_gintmsk.d32);
} else {
DWC_DEBUGPL(DBG_ANY, "gpwrdn=%08x\n", gpwrdn.d32);
......
......@@ -64,6 +64,8 @@ bool microframe_schedule=true;
static const char dwc_driver_name[] = "dwc_otg";
extern void* dummy_send;
extern int pcd_init(
#ifdef LM_INTERFACE
struct lm_device *_dev
......@@ -226,7 +228,7 @@ static struct dwc_otg_driver_module_params dwc_otg_module_params = {
.rx_thr_length = -1,
.pti_enable = -1,
.mpi_enable = -1,
.lpm_enable = -1,
.lpm_enable = 0,
.ic_usb_cap = -1,
.ahb_thr_ratio = -1,
.power_down = -1,
......@@ -238,6 +240,14 @@ static struct dwc_otg_driver_module_params dwc_otg_module_params = {
.adp_enable = -1,
};
//Global variable to switch the fiq fix on or off (declared in bcm2708.c)
extern bool fiq_fix_enable;
// Global variable to enable the split transaction fix
bool fiq_split_enable = true;
//Global variable to switch the nak holdoff on or off
bool nak_holdoff_enable = true;
/**
* This function shows the Driver Version.
*/
......@@ -779,17 +789,33 @@ static int dwc_otg_driver_probe(
_dev->resource->start,
_dev->resource->end - _dev->resource->start + 1);
#if 1
if (!request_mem_region(_dev->resource->start,
_dev->resource->end - _dev->resource->start + 1,
if (!request_mem_region(_dev->resource[0].start,
_dev->resource[0].end - _dev->resource[0].start + 1,
"dwc_otg")) {
dev_dbg(&_dev->dev, "error reserving mapped memory\n");
retval = -EFAULT;
goto fail;
}
dwc_otg_device->os_dep.base = ioremap_nocache(_dev->resource->start,
_dev->resource->end -
_dev->resource->start+1);
dwc_otg_device->os_dep.base = ioremap_nocache(_dev->resource[0].start,
_dev->resource[0].end -
_dev->resource[0].start+1);
if (fiq_fix_enable)
{
if (!request_mem_region(_dev->resource[1].start,
_dev->resource[1].end - _dev->resource[1].start + 1,
"dwc_otg")) {
dev_dbg(&_dev->dev, "error reserving mapped memory\n");
retval = -EFAULT;
goto fail;
}
dwc_otg_device->os_dep.mphi_base = ioremap_nocache(_dev->resource[1].start,
_dev->resource[1].end -
_dev->resource[1].start + 1);
dummy_send = (void *) kmalloc(16, GFP_ATOMIC);
}
#else
{
struct map_desc desc = {
......@@ -1044,6 +1070,12 @@ static int __init dwc_otg_driver_init(void)
int retval = 0;
int error;
struct device_driver *drv;
if(fiq_split_enable && !fiq_fix_enable) {
printk(KERN_WARNING "dwc_otg: fiq_split_enable was set without fiq_fix_enable! Correcting.\n");
fiq_fix_enable = 1;
}
printk(KERN_INFO "%s: version %s (%s bus)\n", dwc_driver_name,
DWC_DRIVER_VERSION,
#ifdef LM_INTERFACE
......@@ -1063,6 +1095,9 @@ static int __init dwc_otg_driver_init(void)
printk(KERN_ERR "%s retval=%d\n", __func__, retval);
return retval;
}
printk(KERN_DEBUG "dwc_otg: FIQ %s\n", fiq_fix_enable ? "enabled":"disabled");
printk(KERN_DEBUG "dwc_otg: NAK holdoff %s\n", nak_holdoff_enable ? "enabled":"disabled");
printk(KERN_DEBUG "dwc_otg: FIQ split fix %s\n", fiq_split_enable ? "enabled":"disabled");
error = driver_create_file(drv, &driver_attr_version);
#ifdef DEBUG
......@@ -1343,6 +1378,13 @@ MODULE_PARM_DESC(otg_ver, "OTG revision supported 0=OTG 1.3 1=OTG 2.0");
module_param(microframe_schedule, bool, 0444);
MODULE_PARM_DESC(microframe_schedule, "Enable the microframe scheduler");
module_param(fiq_fix_enable, bool, 0444);
MODULE_PARM_DESC(fiq_fix_enable, "Enable the fiq fix");
module_param(nak_holdoff_enable, bool, 0444);
MODULE_PARM_DESC(nak_holdoff_enable, "Enable the NAK holdoff");
module_param(fiq_split_enable, bool, 0444);
MODULE_PARM_DESC(fiq_split_enable, "Enable the FIQ fix on split transactions");
/** @page "Module Parameters"
*
* The following parameters may be specified when starting the module.
......
......@@ -40,10 +40,16 @@
* header file.
*/
#ifndef __riscos
#include <linux/usb.h>
#include <linux/usb/hcd.h>
#endif
#include "dwc_otg_hcd.h"
#include "dwc_otg_regs.h"
#include "dwc_otg_mphi_fix.h"
extern bool microframe_schedule;
extern bool microframe_schedule, nak_holdoff_enable;
//#define DEBUG_HOST_CHANNELS
#ifdef DEBUG_HOST_CHANNELS
......@@ -53,6 +59,13 @@ static int last_sel_trans_num_avail_hc_at_start = 0;
static int last_sel_trans_num_avail_hc_at_end = 0;
#endif /* DEBUG_HOST_CHANNELS */
extern int g_next_sched_frame, g_np_count, g_np_sent;
extern haint_data_t haint_saved;
extern hcintmsk_data_t hcintmsk_saved[MAX_EPS_CHANNELS];
extern hcint_data_t hcint_saved[MAX_EPS_CHANNELS];
extern gintsts_data_t ginsts_saved;
dwc_otg_hcd_t *dwc_otg_hcd_alloc_hcd(void)
{
return DWC_ALLOC(sizeof(dwc_otg_hcd_t));
......@@ -162,31 +175,43 @@ static void del_timers(dwc_otg_hcd_t * hcd)
/**
* Processes all the URBs in a single list of QHs. Completes them with
* -ETIMEDOUT and frees the QTD.
* -ESHUTDOWN and frees the QTD.
*/
static void kill_urbs_in_qh_list(dwc_otg_hcd_t * hcd, dwc_list_link_t * qh_list)
{
dwc_list_link_t *qh_item;
dwc_list_link_t *qh_item, *qh_tmp;
dwc_otg_qh_t *qh;
dwc_otg_qtd_t *qtd, *qtd_tmp;
DWC_LIST_FOREACH(qh_item, qh_list) {
DWC_LIST_FOREACH_SAFE(qh_item, qh_tmp, qh_list) {
qh = DWC_LIST_ENTRY(qh_item, dwc_otg_qh_t, qh_list_entry);
DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp,
&qh->qtd_list, qtd_list_entry) {
qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list);
if (qtd->urb != NULL) {
hcd->fops->complete(hcd, qtd->urb->priv,
qtd->urb, -DWC_E_TIMEOUT);
qtd->urb, -DWC_E_SHUTDOWN);
dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
}
}
if(qh->channel) {
/* Using hcchar.chen == 1 is not a reliable test.
* It is possible that the channel has already halted
* but not yet been through the IRQ handler.
*/
dwc_otg_hc_halt(hcd->core_if, qh->channel,
DWC_OTG_HC_XFER_URB_DEQUEUE);
if(microframe_schedule)
hcd->available_host_channels++;
qh->channel = NULL;
}
dwc_otg_hcd_qh_remove(hcd, qh);
}
}
/**
* Responds with an error status of ETIMEDOUT to all URBs in the non-periodic
* Responds with an error status of ESHUTDOWN to all URBs in the non-periodic
* and periodic schedules. The QTD associated with each URB is removed from
* the schedule and freed. This function may be called when a disconnect is
* detected or when the HCD is being stopped.
......@@ -272,7 +297,8 @@ static int32_t dwc_otg_hcd_disconnect_cb(void *p)
*/
dwc_otg_hcd->flags.b.port_connect_status_change = 1;
dwc_otg_hcd->flags.b.port_connect_status = 0;
if(fiq_fix_enable)
local_fiq_disable();
/*
* Shutdown any transfers in process by clearing the Tx FIFO Empty
* interrupt mask and status bits and disabling subsequent host
......@@ -368,8 +394,22 @@ static int32_t dwc_otg_hcd_disconnect_cb(void *p)
channel->qh = NULL;
}
}
if(fiq_split_enable) {
for(i=0; i < 128; i++) {
dwc_otg_hcd->hub_port[i] = 0;
}
haint_saved.d32 = 0;
for(i=0; i < MAX_EPS_CHANNELS; i++) {
hcint_saved[i].d32 = 0;
hcintmsk_saved[i].d32 = 0;
}
}
}
if(fiq_fix_enable)
local_fiq_enable();
if (dwc_otg_hcd->fops->disconnect) {
dwc_otg_hcd->fops->disconnect(dwc_otg_hcd);
}
......@@ -407,6 +447,7 @@ static int dwc_otg_hcd_sleep_cb(void *p)
}
#endif
/**
* HCD Callback function for Remote Wakeup.
*
......@@ -457,10 +498,12 @@ int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * hcd,
dwc_otg_hcd_urb_t * dwc_otg_urb, void **ep_handle,
int atomic_alloc)
{
dwc_irqflags_t flags;
int retval = 0;
uint8_t needs_scheduling = 0;
dwc_otg_transaction_type_e tr_type;
dwc_otg_qtd_t *qtd;
gintmsk_data_t intr_mask = {.d32 = 0 };
hprt0_data_t hprt0 = { .d32 = 0 };
#ifdef DEBUG /* integrity checks (Broadcom) */
if (NULL == hcd->core_if) {
......@@ -475,6 +518,16 @@ int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * hcd,
return -DWC_E_NO_DEVICE;
}
/* Some core configurations cannot support LS traffic on a FS root port */
if ((hcd->fops->speed(hcd, dwc_otg_urb->priv) == USB_SPEED_LOW) &&
(hcd->core_if->hwcfg2.b.fs_phy_type == 1) &&
(hcd->core_if->hwcfg2.b.hs_phy_type == 1)) {
hprt0.d32 = DWC_READ_REG32(hcd->core_if->host_if->hprt0);
if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_FULL_SPEED) {
return -DWC_E_NO_DEVICE;
}
}
qtd = dwc_otg_hcd_qtd_create(dwc_otg_urb, atomic_alloc);
if (qtd == NULL) {
DWC_ERROR("DWC OTG HCD URB Enqueue failed creating QTD\n");
......@@ -490,32 +543,27 @@ int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * hcd,
return -DWC_E_NO_MEMORY;
}
#endif
retval =
dwc_otg_hcd_qtd_add(qtd, hcd, (dwc_otg_qh_t **) ep_handle, atomic_alloc);
intr_mask.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->gintmsk);
if(!intr_mask.b.sofintr) needs_scheduling = 1;
if((((dwc_otg_qh_t *)ep_handle)->ep_type == UE_BULK) && !(qtd->urb->flags & URB_GIVEBACK_ASAP))
/* Do not schedule SG transactions until qtd has URB_GIVEBACK_ASAP set */
needs_scheduling = 0;
retval = dwc_otg_hcd_qtd_add(qtd, hcd, (dwc_otg_qh_t **) ep_handle, atomic_alloc);
// creates a new queue in ep_handle if it doesn't exist already
if (retval < 0) {
DWC_ERROR("DWC OTG HCD URB Enqueue failed adding QTD. "
"Error status %d\n", retval);
dwc_otg_hcd_qtd_free(qtd);
} else {
qtd->qh = *ep_handle;
return retval;
}
intr_mask.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->gintmsk);
if (!intr_mask.b.sofintr && retval == 0) {
dwc_otg_transaction_type_e tr_type;
if ((qtd->qh->ep_type == UE_BULK)
&& !(qtd->urb->flags & URB_GIVEBACK_ASAP)) {
/* Do not schedule SG transactions until qtd has URB_GIVEBACK_ASAP set */
return 0;
}
DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
if(needs_scheduling) {
tr_type = dwc_otg_hcd_select_transactions(hcd);
if (tr_type != DWC_OTG_TRANSACTION_NONE) {
dwc_otg_hcd_queue_transactions(hcd, tr_type);
}
DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
}
return retval;
}
......@@ -524,6 +572,8 @@ int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_t * hcd,
{
dwc_otg_qh_t *qh;
dwc_otg_qtd_t *urb_qtd;
BUG_ON(!hcd);
BUG_ON(!dwc_otg_urb);
#ifdef DEBUG /* integrity checks (Broadcom) */
......@@ -540,14 +590,17 @@ int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_t * hcd,
return -DWC_E_INVALID;
}
urb_qtd = dwc_otg_urb->qtd;
BUG_ON(!urb_qtd);
if (urb_qtd->qh == NULL) {
DWC_ERROR("**** DWC OTG HCD URB Dequeue with QTD with NULL Q handler\n");
return -DWC_E_INVALID;
}
#else
urb_qtd = dwc_otg_urb->qtd;
BUG_ON(!urb_qtd);
#endif
qh = urb_qtd->qh;
BUG_ON(!qh);
if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
if (urb_qtd->in_process) {
dump_channel_info(hcd, qh);
......@@ -571,6 +624,8 @@ int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_t * hcd,
*/
dwc_otg_hc_halt(hcd->core_if, qh->channel,
DWC_OTG_HC_XFER_URB_DEQUEUE);
dwc_otg_hcd_release_port(hcd, qh);
}
}
......@@ -687,6 +742,35 @@ static void reset_tasklet_func(void *data)
dwc_otg_hcd->flags.b.port_reset_change = 1;
}
#ifndef __riscos
static void completion_tasklet_func(void *ptr)
{
dwc_otg_hcd_t *hcd = (dwc_otg_hcd_t *) ptr;
struct urb *urb;
urb_tq_entry_t *item;
dwc_irqflags_t flags;
/* This could just be spin_lock_irq */
DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
while (!DWC_TAILQ_EMPTY(&hcd->completed_urb_list)) {
item = DWC_TAILQ_FIRST(&hcd->completed_urb_list);
urb = item->urb;
DWC_TAILQ_REMOVE(&hcd->completed_urb_list, item,
urb_tq_entries);
DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
DWC_FREE(item);
usb_hcd_giveback_urb(hcd->priv, urb, urb->status);
fiq_print(FIQDBG_PORTHUB, "COMPLETE");
DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
}
DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
return;
}
#endif
static void qh_list_free(dwc_otg_hcd_t * hcd, dwc_list_link_t * qh_list)
{
dwc_list_link_t *item,*item_tmp;
......@@ -819,12 +903,16 @@ static void dwc_otg_hcd_free(dwc_otg_hcd_t * dwc_otg_hcd)