From b0a3e61a589daf0438f4012146282cff2add11a2 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 13 Dec 2014 11:55:11 +0000 Subject: brcm2708: remove linux 3.10 support Signed-off-by: Felix Fietkau git-svn-id: svn://svn.openwrt.org/openwrt/trunk@43687 3c298f89-4303-0410-b956-a3cf2f4a3e73 --- ...ing-a-FIQ-to-implement-split-transactions.patch | 1421 -------------------- 1 file changed, 1421 deletions(-) delete mode 100644 target/linux/brcm2708/patches-3.10/0072-USB-fix-using-a-FIQ-to-implement-split-transactions.patch (limited to 'target/linux/brcm2708/patches-3.10/0072-USB-fix-using-a-FIQ-to-implement-split-transactions.patch') diff --git a/target/linux/brcm2708/patches-3.10/0072-USB-fix-using-a-FIQ-to-implement-split-transactions.patch b/target/linux/brcm2708/patches-3.10/0072-USB-fix-using-a-FIQ-to-implement-split-transactions.patch deleted file mode 100644 index b315baf3bb..0000000000 --- a/target/linux/brcm2708/patches-3.10/0072-USB-fix-using-a-FIQ-to-implement-split-transactions.patch +++ /dev/null @@ -1,1421 +0,0 @@ -From 0b8275da8346466af37b50d5ba687a386df9b0f4 Mon Sep 17 00:00:00 2001 -From: Gordon Hollingworth -Date: Thu, 4 Apr 2013 11:05:21 +0100 -Subject: [PATCH 072/196] USB fix using a FIQ to implement split transactions - -This commit adds a FIQ implementaion that schedules -the split transactions using a FIQ so we don't get -held off by the interrupt latency of Linux ---- - .../usb/host/dwc_common_port/dwc_common_linux.c | 7 +- - drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c | 37 +- - drivers/usb/host/dwc_otg/dwc_otg_driver.c | 6 +- - drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 125 ++++- - drivers/usb/host/dwc_otg/dwc_otg_hcd.h | 20 +- - drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 538 ++++++++++++++++++--- - drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 18 +- - drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c | 31 +- - drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.h | 26 +- - drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c | 2 +- - 10 files changed, 696 insertions(+), 114 deletions(-) - -diff --git a/drivers/usb/host/dwc_common_port/dwc_common_linux.c b/drivers/usb/host/dwc_common_port/dwc_common_linux.c -index 6814e51..0812d3a 100644 ---- a/drivers/usb/host/dwc_common_port/dwc_common_linux.c -+++ b/drivers/usb/host/dwc_common_port/dwc_common_linux.c -@@ -580,7 +580,12 @@ void DWC_WRITE_REG64(uint64_t volatile *reg, uint64_t value) - - void DWC_MODIFY_REG32(uint32_t volatile *reg, uint32_t clear_mask, uint32_t set_mask) - { -+ unsigned long flags; -+ -+ local_irq_save(flags); -+ local_fiq_disable(); - writel((readl(reg) & ~clear_mask) | set_mask, reg); -+ local_irq_restore(flags); - } - - #if 0 -@@ -1301,7 +1306,7 @@ EXPORT_SYMBOL(DWC_EXCEPTION); - EXPORT_SYMBOL(__DWC_DEBUG); - #endif - --EXPORT_SYMBOL(__DWC_DMA_ALLOC); -+EXPORT_SYMBOL(__DWC_DMA_ALLOC); - EXPORT_SYMBOL(__DWC_DMA_ALLOC_ATOMIC); - EXPORT_SYMBOL(__DWC_DMA_FREE); - EXPORT_SYMBOL(__DWC_ALLOC); -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c -index b861b55..b5a007d 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c -@@ -47,8 +47,6 @@ - #include "dwc_otg_hcd.h" - #include "dwc_otg_mphi_fix.h" - --extern bool fiq_fix_enable; -- - #ifdef DEBUG - inline const char *op_state_str(dwc_otg_core_if_t * core_if) - { -@@ -1321,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; -@@ -1338,19 +1336,33 @@ 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 -@@ -1394,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; -@@ -1415,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); -@@ -1512,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); - -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_driver.c b/drivers/usb/host/dwc_otg/dwc_otg_driver.c -index cea8fcb..6c89a69 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_driver.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_driver.c -@@ -242,7 +242,8 @@ static struct dwc_otg_driver_module_params dwc_otg_module_params = { - - //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; - -@@ -1090,6 +1091,7 @@ static int __init dwc_otg_driver_init(void) - } - 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 -@@ -1374,6 +1376,8 @@ 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" - * -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -index 9c2e71a..af9108c 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -@@ -45,6 +45,7 @@ - - #include "dwc_otg_hcd.h" - #include "dwc_otg_regs.h" -+#include "dwc_otg_mphi_fix.h" - - extern bool microframe_schedule, nak_holdoff_enable; - -@@ -581,6 +582,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); - } - } - -@@ -716,6 +719,8 @@ static void completion_tasklet_func(void *ptr) - - 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); -@@ -979,6 +984,10 @@ int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd, dwc_otg_core_if_t * core_if) - hcd->frame_list = NULL; - hcd->frame_list_dma = 0; - hcd->periodic_qh_count = 0; -+ -+ DWC_MEMSET(hcd->hub_port, 0, sizeof(hcd->hub_port)); -+ DWC_MEMSET(hcd->hub_port_alloc, -1, sizeof(hcd->hub_port_alloc)); -+ - out: - return retval; - } -@@ -1124,7 +1133,12 @@ static void assign_and_init_hc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) - uint32_t hub_addr, port_addr; - hc->do_split = 1; - hc->xact_pos = qtd->isoc_split_pos; -- hc->complete_split = qtd->complete_split; -+ /* We don't need to do complete splits anymore */ -+ if(fiq_split_enable) -+ hc->complete_split = qtd->complete_split = 0; -+ else -+ hc->complete_split = qtd->complete_split; -+ - hcd->fops->hub_info(hcd, urb->priv, &hub_addr, &port_addr); - hc->hub_addr = (uint8_t) hub_addr; - hc->port_addr = (uint8_t) port_addr; -@@ -1271,6 +1285,62 @@ static void assign_and_init_hc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) - hc->qh = qh; - } - -+/* -+** Check the transaction to see if the port / hub has already been assigned for -+** a split transaction -+** -+** Return 0 - Port is already in use -+*/ -+int dwc_otg_hcd_allocate_port(dwc_otg_hcd_t * hcd, dwc_otg_qh_t *qh) -+{ -+ uint32_t hub_addr, port_addr; -+ -+ if(!fiq_split_enable) -+ return 0; -+ -+ hcd->fops->hub_info(hcd, DWC_CIRCLEQ_FIRST(&qh->qtd_list)->urb->priv, &hub_addr, &port_addr); -+ -+ if(hcd->hub_port[hub_addr] & (1 << port_addr)) -+ { -+ fiq_print(FIQDBG_PORTHUB, "H%dP%d:S%02d", hub_addr, port_addr, qh->skip_count); -+ -+ qh->skip_count++; -+ -+ if(qh->skip_count > 40000) -+ { -+ printk_once(KERN_ERR "Error: Having to skip port allocation"); -+ local_fiq_disable(); -+ BUG(); -+ return 0; -+ } -+ return 1; -+ } -+ else -+ { -+ qh->skip_count = 0; -+ hcd->hub_port[hub_addr] |= 1 << port_addr; -+ fiq_print(FIQDBG_PORTHUB, "H%dP%d:A %d", hub_addr, port_addr, DWC_CIRCLEQ_FIRST(&qh->qtd_list)->urb->pipe_info.ep_num); -+ hcd->hub_port_alloc[hub_addr * 16 + port_addr] = dwc_otg_hcd_get_frame_number(hcd); -+ return 0; -+ } -+} -+void dwc_otg_hcd_release_port(dwc_otg_hcd_t * hcd, dwc_otg_qh_t *qh) -+{ -+ uint32_t hub_addr, port_addr; -+ -+ if(!fiq_split_enable) -+ return; -+ -+ hcd->fops->hub_info(hcd, DWC_CIRCLEQ_FIRST(&qh->qtd_list)->urb->priv, &hub_addr, &port_addr); -+ -+ hcd->hub_port[hub_addr] &= ~(1 << port_addr); -+ hcd->hub_port_alloc[hub_addr * 16 + port_addr] = -1; -+ -+ fiq_print(FIQDBG_PORTHUB, "H%dP%d:RO%d", hub_addr, port_addr, DWC_CIRCLEQ_FIRST(&qh->qtd_list)->urb->pipe_info.ep_num); -+ -+} -+ -+ - /** - * This function selects transactions from the HCD transfer schedule and - * assigns them to available host channels. It is called from HCD interrupt -@@ -1304,11 +1374,22 @@ dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd) - - while (qh_ptr != &hcd->periodic_sched_ready && - !DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) { -+ -+ qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry); -+ -+ if(qh->do_split && dwc_otg_hcd_allocate_port(hcd, qh)) -+ { -+ qh_ptr = DWC_LIST_NEXT(qh_ptr); -+ g_next_sched_frame = dwc_frame_num_inc(dwc_otg_hcd_get_frame_number(hcd), 1); -+ continue; -+ } -+ - if (microframe_schedule) { - // Make sure we leave one channel for non periodic transactions. - DWC_SPINLOCK_IRQSAVE(channel_lock, &flags); - if (hcd->available_host_channels <= 1) { - DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags); -+ if(qh->do_split) dwc_otg_hcd_release_port(hcd, qh); - break; - } - hcd->available_host_channels--; -@@ -1329,8 +1410,6 @@ dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd) - DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_assigned, - &qh->qh_list_entry); - DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags); -- -- ret_val = DWC_OTG_TRANSACTION_PERIODIC; - } - - /* -@@ -1369,10 +1448,19 @@ dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd) - qh->nak_frame = 0xffff; - } - } -+ -+ if (qh->do_split && dwc_otg_hcd_allocate_port(hcd, qh)) -+ { -+ g_next_sched_frame = dwc_frame_num_inc(dwc_otg_hcd_get_frame_number(hcd), 1); -+ qh_ptr = DWC_LIST_NEXT(qh_ptr); -+ continue; -+ } -+ - if (microframe_schedule) { - DWC_SPINLOCK_IRQSAVE(channel_lock, &flags); - if (hcd->available_host_channels < 1) { - DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags); -+ if(qh->do_split) dwc_otg_hcd_release_port(hcd, qh); - break; - } - hcd->available_host_channels--; -@@ -1396,16 +1484,17 @@ dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd) - - g_np_sent++; - -- if (ret_val == DWC_OTG_TRANSACTION_NONE) { -- ret_val = DWC_OTG_TRANSACTION_NON_PERIODIC; -- } else { -- ret_val = DWC_OTG_TRANSACTION_ALL; -- } -- - if (!microframe_schedule) - hcd->non_periodic_channels++; - } - -+ if(!DWC_LIST_EMPTY(&hcd->periodic_sched_assigned)) -+ ret_val |= DWC_OTG_TRANSACTION_PERIODIC; -+ -+ if(!DWC_LIST_EMPTY(&hcd->non_periodic_sched_active)) -+ ret_val |= DWC_OTG_TRANSACTION_NON_PERIODIC; -+ -+ - #ifdef DEBUG_HOST_CHANNELS - last_sel_trans_num_avail_hc_at_end = hcd->available_host_channels; - #endif /* DEBUG_HOST_CHANNELS */ -@@ -1522,6 +1611,15 @@ static void process_periodic_channels(dwc_otg_hcd_t * hcd) - - qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry); - -+ // Do not send a split start transaction any later than frame .6 -+ // Note, we have to schedule a periodic in .5 to make it go in .6 -+ if(fiq_split_enable && qh->do_split && ((dwc_otg_hcd_get_frame_number(hcd) + 1) & 7) > 6) -+ { -+ qh_ptr = qh_ptr->next; -+ g_next_sched_frame = dwc_otg_hcd_get_frame_number(hcd) | 7; -+ continue; -+ } -+ - /* - * Set a flag if we're queuing high-bandwidth in slave mode. - * The flag prevents any halts to get into the request queue in -@@ -1651,6 +1749,15 @@ static void process_non_periodic_channels(dwc_otg_hcd_t * hcd) - - qh = DWC_LIST_ENTRY(hcd->non_periodic_qh_ptr, dwc_otg_qh_t, - qh_list_entry); -+ -+ // Do not send a split start transaction any later than frame .5 -+ // non periodic transactions will start immediately in this uframe -+ if(fiq_split_enable && qh->do_split && ((dwc_otg_hcd_get_frame_number(hcd) + 1) & 7) > 6) -+ { -+ g_next_sched_frame = dwc_otg_hcd_get_frame_number(hcd) | 7; -+ break; -+ } -+ - status = - queue_transaction(hcd, qh->channel, - tx_status.b.nptxfspcavail); -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd.h b/drivers/usb/host/dwc_otg/dwc_otg_hcd.h -index 0493dbf..d3d6e997 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.h -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.h -@@ -168,10 +168,10 @@ typedef enum dwc_otg_control_phase { - - /** Transaction types. */ - typedef enum dwc_otg_transaction_type { -- DWC_OTG_TRANSACTION_NONE, -- DWC_OTG_TRANSACTION_PERIODIC, -- DWC_OTG_TRANSACTION_NON_PERIODIC, -- DWC_OTG_TRANSACTION_ALL -+ DWC_OTG_TRANSACTION_NONE = 0, -+ DWC_OTG_TRANSACTION_PERIODIC = 1, -+ DWC_OTG_TRANSACTION_NON_PERIODIC = 2, -+ DWC_OTG_TRANSACTION_ALL = DWC_OTG_TRANSACTION_PERIODIC + DWC_OTG_TRANSACTION_NON_PERIODIC - } dwc_otg_transaction_type_e; - - struct dwc_otg_qh; -@@ -370,6 +370,8 @@ typedef struct dwc_otg_qh { - - uint16_t speed; - uint16_t frame_usecs[8]; -+ -+ uint32_t skip_count; - } dwc_otg_qh_t; - - DWC_CIRCLEQ_HEAD(hc_list, dwc_hc); -@@ -574,6 +576,10 @@ struct dwc_otg_hcd { - /** Frame List */ - uint32_t *frame_list; - -+ /** Hub - Port assignment */ -+ int hub_port[16]; -+ int hub_port_alloc[256]; -+ - /** Frame List DMA address */ - dma_addr_t frame_list_dma; - -@@ -604,12 +610,16 @@ extern dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t - extern void dwc_otg_hcd_queue_transactions(dwc_otg_hcd_t * hcd, - dwc_otg_transaction_type_e tr_type); - -+int dwc_otg_hcd_allocate_port(dwc_otg_hcd_t * hcd, dwc_otg_qh_t *qh); -+void dwc_otg_hcd_release_port(dwc_otg_hcd_t * dwc_otg_hcd, dwc_otg_qh_t *qh); -+ -+ - /** @} */ - - /** @name Interrupt Handler Functions */ - /** @{ */ - extern int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd); --extern int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * dwc_otg_hcd, int32_t); -+extern int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * dwc_otg_hcd); - extern int32_t dwc_otg_hcd_handle_rx_status_q_level_intr(dwc_otg_hcd_t * - dwc_otg_hcd); - extern int32_t dwc_otg_hcd_handle_np_tx_fifo_empty_intr(dwc_otg_hcd_t * -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -index 16e8c6c..e8b4d35 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -@@ -38,6 +38,7 @@ - - #include - #include -+#include - - - extern bool microframe_schedule; -@@ -52,21 +53,295 @@ extern bool microframe_schedule; - - void * dummy_send; - mphi_regs_t c_mphi_regs; -+volatile void *dwc_regs_base; - int fiq_done, int_done; --int g_next_sched_frame, g_np_count, g_np_sent, g_work_expected; --static int mphi_int_count = 0 ; - --extern bool fiq_fix_enable, nak_holdoff_enable; -+gintsts_data_t gintsts_saved = {.d32 = 0}; -+hcint_data_t hcint_saved[MAX_EPS_CHANNELS]; -+hcintmsk_data_t hcintmsk_saved[MAX_EPS_CHANNELS]; -+int split_out_xfersize[MAX_EPS_CHANNELS]; -+haint_data_t haint_saved; -+ -+int g_next_sched_frame, g_np_count, g_np_sent; -+static int mphi_int_count = 0 ; - - hcchar_data_t nak_hcchar; - hctsiz_data_t nak_hctsiz; - hcsplt_data_t nak_hcsplt; - int nak_count; - -+int complete_sched[MAX_EPS_CHANNELS] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; -+int split_start_frame[MAX_EPS_CHANNELS]; -+int queued_port[MAX_EPS_CHANNELS]; -+ -+#ifdef FIQ_DEBUG -+char buffer[1000*16]; -+int wptr; -+void _fiq_print(FIQDBG_T dbg_lvl, char *fmt, ...) -+{ -+ FIQDBG_T dbg_lvl_req = FIQDBG_PORTHUB; -+ va_list args; -+ char text[17]; -+ hfnum_data_t hfnum = { .d32 = FIQ_READ(dwc_regs_base + 0x408) }; -+ unsigned long flags; -+ -+ local_irq_save(flags); -+ local_fiq_disable(); -+ if(dbg_lvl & dbg_lvl_req || dbg_lvl == FIQDBG_ERR) -+ { -+ snprintf(text, 9, "%4d%d:%d ", hfnum.b.frnum/8, hfnum.b.frnum%8, 8 - hfnum.b.frrem/937); -+ va_start(args, fmt); -+ vsnprintf(text+8, 9, fmt, args); -+ va_end(args); -+ -+ memcpy(buffer + wptr, text, 16); -+ wptr = (wptr + 16) % sizeof(buffer); -+ } -+ local_irq_restore(flags); -+} -+#endif -+ -+void fiq_queue_request(int channel, int odd_frame) -+{ -+ hcchar_data_t hcchar = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0x0) }; -+ hcsplt_data_t hcsplt = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0x4) }; -+ hctsiz_data_t hctsiz = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0x10) }; -+ -+ if(hcsplt.b.spltena == 0) -+ { -+ fiq_print(FIQDBG_ERR, "SPLTENA "); -+ BUG(); -+ } -+ -+ if(hcchar.b.epdir == 1) -+ { -+ fiq_print(FIQDBG_SCHED, "IN Ch %d", channel); -+ } -+ else -+ { -+ hctsiz.b.xfersize = 0; -+ fiq_print(FIQDBG_SCHED, "OUT Ch %d", channel); -+ } -+ FIQ_WRITE((dwc_regs_base + 0x500 + (channel * 0x20) + 0x10), hctsiz.d32); -+ -+ hcsplt.b.compsplt = 1; -+ FIQ_WRITE((dwc_regs_base + 0x500 + (channel * 0x20) + 0x4), hcsplt.d32); -+ -+ // Send the Split complete -+ hcchar.b.chen = 1; -+ hcchar.b.oddfrm = odd_frame ? 1 : 0; -+ -+ // Post this for transmit on the next frame for periodic or this frame for non-periodic -+ fiq_print(FIQDBG_SCHED, "SND_%s", odd_frame ? "ODD " : "EVEN"); -+ -+ FIQ_WRITE((dwc_regs_base + 0x500 + (channel * 0x20) + 0x0), hcchar.d32); -+} -+ -+static int last_sof = -1; -+ -+/* -+** Function to handle the start of frame interrupt, choose whether we need to do anything and -+** therefore trigger the main interrupt -+** -+** returns int != 0 - interrupt has been handled -+*/ -+int diff; -+ -+int fiq_sof_handle(hfnum_data_t hfnum) -+{ -+ int handled = 0; -+ int i; -+ -+ // Just check that once we're running we don't miss a SOF -+ /*if(last_sof != -1 && (hfnum.b.frnum != ((last_sof + 1) & 0x3fff))) -+ { -+ fiq_print(FIQDBG_ERR, "LASTSOF "); -+ fiq_print(FIQDBG_ERR, "%4d%d ", last_sof / 8, last_sof & 7); -+ fiq_print(FIQDBG_ERR, "%4d%d ", hfnum.b.frnum / 8, hfnum.b.frnum & 7); -+ BUG(); -+ }*/ -+ -+ // Only start remembering the last sof when the interrupt has been -+ // enabled (we don't check the mask to come in here...) -+ if(last_sof != -1 || FIQ_READ(dwc_regs_base + 0x18) & (1<<3)) -+ last_sof = hfnum.b.frnum; -+ -+ for(i = 0; i < MAX_EPS_CHANNELS; i++) -+ { -+ if(complete_sched[i] != -1) -+ { -+ if(complete_sched[i] <= hfnum.b.frnum || (complete_sched[i] > 0x3f00 && hfnum.b.frnum < 0xf0)) -+ { -+ fiq_queue_request(i, hfnum.b.frnum & 1); -+ complete_sched[i] = -1; -+ } -+ } -+ -+ if(complete_sched[i] != -1) -+ { -+ // This is because we've seen a split complete occur with no start... -+ // most likely because missed the complete 0x3fff frames ago! -+ -+ diff = (hfnum.b.frnum + 0x3fff - complete_sched[i]) & 0x3fff ; -+ if(diff > 32 && diff < 0x3f00) -+ { -+ fiq_print(FIQDBG_ERR, "SPLTMISS"); -+ BUG(); -+ } -+ } -+ } -+ -+ if(g_np_count == g_np_sent && dwc_frame_num_gt(g_next_sched_frame, hfnum.b.frnum)) -+ { -+ /* -+ * If np_count != np_sent that means we need to queue non-periodic (bulk) packets this packet -+ * g_next_sched_frame is the next frame we have periodic packets for -+ * -+ * if neither of these are required for this frame then just clear the interrupt -+ */ -+ handled = 1; -+ -+ } -+ -+ return handled; -+} -+ -+int port_id(hcsplt_data_t hcsplt) -+{ -+ return hcsplt.b.prtaddr + (hcsplt.b.hubaddr << 8); -+} -+ -+int fiq_hcintr_handle(int channel, hfnum_data_t hfnum) -+{ -+ hcchar_data_t hcchar = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0x0) }; -+ hcsplt_data_t hcsplt = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0x4) }; -+ hcint_data_t hcint = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0x8) }; -+ hcintmsk_data_t hcintmsk = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0xc) }; -+ hctsiz_data_t hctsiz = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0x10)}; -+ -+ hcint_saved[channel].d32 |= hcint.d32; -+ hcintmsk_saved[channel].d32 = hcintmsk.d32; -+ -+ if(hcsplt.b.spltena) -+ { -+ fiq_print(FIQDBG_PORTHUB, "ph: %4x", port_id(hcsplt)); -+ if(hcint.b.chhltd) -+ { -+ fiq_print(FIQDBG_SCHED, "CH HLT %d", channel); -+ fiq_print(FIQDBG_SCHED, "%08x", hcint_saved[channel]); -+ } -+ if(hcint.b.stall || hcint.b.xacterr || hcint.b.bblerr || hcint.b.frmovrun || hcint.b.datatglerr) -+ { -+ queued_port[channel] = 0; -+ fiq_print(FIQDBG_ERR, "CHAN ERR"); -+ } -+ if(hcint.b.xfercomp) -+ { -+ // Clear the port allocation and transmit anything also on this port -+ queued_port[channel] = 0; -+ fiq_print(FIQDBG_SCHED, "XFERCOMP"); -+ } -+ if(hcint.b.nak) -+ { -+ queued_port[channel] = 0; -+ fiq_print(FIQDBG_SCHED, "NAK"); -+ } -+ if(hcint.b.ack && !hcsplt.b.compsplt) -+ { -+ int i; -+ -+ // Do not complete isochronous out transactions -+ if(hcchar.b.eptype == 1 && hcchar.b.epdir == 0) -+ { -+ queued_port[channel] = 0; -+ fiq_print(FIQDBG_SCHED, "ISOC_OUT"); -+ } -+ else -+ { -+ // Make sure we check the port / hub combination that we sent this split on. -+ // Do not queue a second request to the same port -+ for(i = 0; i < MAX_EPS_CHANNELS; i++) -+ { -+ if(port_id(hcsplt) == queued_port[i]) -+ { -+ fiq_print(FIQDBG_ERR, "PORTERR "); -+ //BUG(); -+ } -+ } -+ -+ split_start_frame[channel] = (hfnum.b.frnum + 1) & ~7; -+ -+ // Note, the size of an OUT is in the start split phase, not -+ // the complete split -+ split_out_xfersize[channel] = hctsiz.b.xfersize; -+ -+ hcint_saved[channel].b.chhltd = 0; -+ hcint_saved[channel].b.ack = 0; -+ -+ queued_port[channel] = port_id(hcsplt); -+ -+ if(hcchar.b.eptype & 1) -+ { -+ // Send the periodic complete in the same oddness frame as the ACK went... -+ fiq_queue_request(channel, !(hfnum.b.frnum & 1)); -+ // complete_sched[channel] = dwc_frame_num_inc(hfnum.b.frnum, 1); -+ } -+ else -+ { -+ // Schedule the split complete to occur later -+ complete_sched[channel] = dwc_frame_num_inc(hfnum.b.frnum, 2); -+ fiq_print(FIQDBG_SCHED, "ACK%04d%d", complete_sched[channel]/8, complete_sched[channel]%8); -+ } -+ } -+ } -+ if(hcint.b.nyet) -+ { -+ fiq_print(FIQDBG_ERR, "NYETERR1"); -+ //BUG(); -+ // Can transmit a split complete up to uframe .0 of the next frame -+ if(hfnum.b.frnum <= dwc_frame_num_inc(split_start_frame[channel], 8)) -+ { -+ // Send it next frame -+ if(hcchar.b.eptype & 1) // type 1 & 3 are interrupt & isoc -+ { -+ fiq_print(FIQDBG_SCHED, "NYT:SEND"); -+ fiq_queue_request(channel, !(hfnum.b.frnum & 1)); -+ } -+ else -+ { -+ // Schedule non-periodic access for next frame (the odd-even bit doesn't effect NP) -+ complete_sched[channel] = dwc_frame_num_inc(hfnum.b.frnum, 1); -+ fiq_print(FIQDBG_SCHED, "NYT%04d%d", complete_sched[channel]/8, complete_sched[channel]%8); -+ } -+ hcint_saved[channel].b.chhltd = 0; -+ hcint_saved[channel].b.nyet = 0; -+ } -+ else -+ { -+ queued_port[channel] = 0; -+ fiq_print(FIQDBG_ERR, "NYETERR2"); -+ //BUG(); -+ } -+ } -+ } -+ -+ // Clear the interrupt, this will also clear the HAINT bit -+ FIQ_WRITE((dwc_regs_base + 0x500 + (channel * 0x20) + 0x8), hcint.d32); -+ return hcint_saved[channel].d32 == 0; -+} -+ -+gintsts_data_t gintsts; -+gintmsk_data_t gintmsk; -+// triggered: The set of interrupts that were triggered -+// handled: The set of interrupts that have been handled (no IRQ is -+// required) -+// keep: The set of interrupts we want to keep unmasked even though we -+// want to trigger an IRQ to handle it (SOF and HCINTR) -+gintsts_data_t triggered, handled, keep; -+hfnum_data_t hfnum; -+ - void __attribute__ ((naked)) dwc_otg_hcd_handle_fiq(void) - { -- gintsts_data_t gintsts; -- hfnum_data_t hfnum; - - /* entry takes care to store registers we will be treading on here */ - asm __volatile__ ( -@@ -74,43 +349,112 @@ void __attribute__ ((naked)) dwc_otg_hcd_handle_fiq(void) - /* stash FIQ and normal regs */ - "stmdb sp!, {r0-r12, lr};" - /* !! THIS SETS THE FRAME, adjust to > sizeof locals */ -- "sub fp, ip, #256 ;" -+ "sub fp, ip, #512 ;" - ); - -- fiq_done++; -- gintsts.d32 = FIQ_READ_IO_ADDRESS(USB_BASE + 0x14) & FIQ_READ_IO_ADDRESS(USB_BASE + 0x18); -- hfnum.d32 = FIQ_READ_IO_ADDRESS(USB_BASE + 0x408); -- -- if(gintsts.d32) -+ // Cannot put local variables at the beginning of the function -+ // because otherwise 'C' will play with the stack pointer. any locals -+ // need to be inside the following block -+ do - { -- if(gintsts.b.sofintr && g_np_count == g_np_sent && dwc_frame_num_gt(g_next_sched_frame, hfnum.b.frnum)) -+ fiq_done++; -+ gintsts.d32 = FIQ_READ(dwc_regs_base + 0x14); -+ gintmsk.d32 = FIQ_READ(dwc_regs_base + 0x18); -+ hfnum.d32 = FIQ_READ(dwc_regs_base + 0x408); -+ triggered.d32 = gintsts.d32 & gintmsk.d32; -+ handled.d32 = 0; -+ keep.d32 = 0; -+ fiq_print(FIQDBG_INT, "FIQ "); -+ fiq_print(FIQDBG_INT, "%08x", gintsts.d32); -+ fiq_print(FIQDBG_INT, "%08x", gintmsk.d32); -+ if(gintsts.d32) - { -- /* -- * If np_count != np_sent that means we need to queue non-periodic (bulk) packets this packet -- * g_next_sched_frame is the next frame we have periodic packets for -- * -- * if neither of these are required for this frame then just clear the interrupt -- */ -- gintsts.d32 = 0; -- gintsts.b.sofintr = 1; -- FIQ_WRITE_IO_ADDRESS((USB_BASE + 0x14), gintsts.d32); -+ // If port enabled -+ if((FIQ_READ(dwc_regs_base + 0x440) & 0xf) == 0x5) -+ { -+ if(gintsts.b.sofintr) -+ { -+ if(fiq_sof_handle(hfnum)) -+ { -+ handled.b.sofintr = 1; /* Handled in FIQ */ -+ } -+ else -+ { -+ /* Keer interrupt unmasked */ -+ keep.b.sofintr = 1; -+ } -+ { -+ // Need to make sure the read and clearing of the SOF interrupt is as close as possible to avoid the possibility of missing -+ // a start of frame interrupt -+ gintsts_data_t gintsts = { .b.sofintr = 1 }; -+ FIQ_WRITE((dwc_regs_base + 0x14), gintsts.d32); -+ } -+ } -+ -+ if(fiq_split_enable && gintsts.b.hcintr) -+ { -+ int i; -+ haint_data_t haint; -+ haintmsk_data_t haintmsk; -+ -+ haint.d32 = FIQ_READ(dwc_regs_base + 0x414); -+ haintmsk.d32 = FIQ_READ(dwc_regs_base + 0x418); -+ haint.d32 &= haintmsk.d32; -+ haint_saved.d32 |= haint.d32; -+ -+ fiq_print(FIQDBG_INT, "hcintr"); -+ fiq_print(FIQDBG_INT, "%08x", FIQ_READ(dwc_regs_base + 0x414)); -+ -+ // Go through each channel that has an enabled interrupt -+ for(i = 0; i < 16; i++) -+ if((haint.d32 >> i) & 1) -+ if(fiq_hcintr_handle(i, hfnum)) -+ haint_saved.d32 &= ~(1 << i); /* this was handled */ -+ -+ /* If we've handled all host channel interrupts then don't trigger the interrupt */ -+ if(haint_saved.d32 == 0) -+ { -+ handled.b.hcintr = 1; -+ } -+ else -+ { -+ /* Make sure we keep the channel interrupt unmasked when triggering the IRQ */ -+ keep.b.hcintr = 1; -+ } - -- g_work_expected = 0; -+ { -+ gintsts_data_t gintsts = { .b.hcintr = 1 }; -+ -+ // Always clear the channel interrupt -+ FIQ_WRITE((dwc_regs_base + 0x14), gintsts.d32); -+ } -+ } -+ } -+ else -+ { -+ last_sof = -1; -+ } - } -- else -+ -+ // Mask out the interrupts triggered - those handled - don't mask out the ones we want to keep -+ gintmsk.d32 = keep.d32 | (gintmsk.d32 & ~(triggered.d32 & ~handled.d32)); -+ // Save those that were triggered but not handled -+ gintsts_saved.d32 |= triggered.d32 & ~handled.d32; -+ FIQ_WRITE(dwc_regs_base + 0x18, gintmsk.d32); -+ -+ // Clear and save any unhandled interrupts and trigger the interrupt -+ if(gintsts_saved.d32) - { -- g_work_expected = 1; - /* To enable the MPHI interrupt (INT 32) - */ -- FIQ_WRITE( c_mphi_regs.outdda, (int) dummy_send); -+ FIQ_WRITE( c_mphi_regs.outdda, (int) dummy_send); - FIQ_WRITE( c_mphi_regs.outddb, (1 << 29)); - - mphi_int_count++; -- /* Clear the USB global interrupt so we don't just sit in the FIQ */ -- FIQ_MODIFY_IO_ADDRESS((USB_BASE + 0x8),1,0); -- - } - } -+ while(0); -+ - mb(); - - /* exit back to normal mode restoring everything */ -@@ -133,6 +477,7 @@ int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd) - - dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if; - gintsts_data_t gintsts; -+ gintmsk_data_t gintmsk; - hfnum_data_t hfnum; - - #ifdef DEBUG -@@ -140,6 +485,9 @@ int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd) - - #endif - -+ gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts); -+ gintmsk.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintmsk); -+ - /* Exit from ISR if core is hibernated */ - if (core_if->hibernation_suspend == 1) { - goto exit_handler_routine; -@@ -147,11 +495,18 @@ int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd) - DWC_SPINLOCK(dwc_otg_hcd->lock); - /* Check if HOST Mode */ - if (dwc_otg_is_host_mode(core_if)) { -- gintsts.d32 = dwc_otg_read_core_intr(core_if); -+ local_fiq_disable(); -+ gintmsk.d32 |= gintsts_saved.d32; -+ gintsts.d32 |= gintsts_saved.d32; -+ gintsts_saved.d32 = 0; -+ local_fiq_enable(); - if (!gintsts.d32) { - goto exit_handler_routine; - } -+ gintsts.d32 &= gintmsk.d32; -+ - #ifdef DEBUG -+ // We should be OK doing this because the common interrupts should already have been serviced - /* Don't print debug message in the interrupt handler on SOF */ - #ifndef DEBUG_SOF - if (gintsts.d32 != DWC_SOF_INTR_MASK) -@@ -171,11 +526,12 @@ int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd) - if (gintsts.b.sofintr && g_np_count == g_np_sent && dwc_frame_num_gt(g_next_sched_frame, hfnum.b.frnum)) - { - /* Note, we should never get here if the FIQ is doing it's job properly*/ -- retval |= dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd, g_work_expected); -+ retval |= dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd); - } - else if (gintsts.b.sofintr) { -- retval |= dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd, g_work_expected); -+ retval |= dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd); - } -+ - if (gintsts.b.rxstsqlvl) { - retval |= - dwc_otg_hcd_handle_rx_status_q_level_intr -@@ -190,7 +546,10 @@ int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd) - /** @todo Implement i2cintr handler. */ - } - if (gintsts.b.portintr) { -+ -+ gintmsk_data_t gintmsk = { .b.portintr = 1}; - retval |= dwc_otg_hcd_handle_port_intr(dwc_otg_hcd); -+ DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0, gintmsk.d32); - } - if (gintsts.b.hcintr) { - retval |= dwc_otg_hcd_handle_hc_intr(dwc_otg_hcd); -@@ -227,26 +586,35 @@ exit_handler_routine: - - if (fiq_fix_enable) - { -- /* Clear the MPHI interrupt */ -- DWC_WRITE_REG32(c_mphi_regs.intstat, (1<<16)); -- if (mphi_int_count >= 60) -+ local_fiq_disable(); -+ // Make sure that we don't clear the interrupt if we've still got pending work to do -+ if(gintsts_saved.d32 == 0) - { -- DWC_WRITE_REG32(c_mphi_regs.ctrl, ((1<<31) + (1<<16))); -- while(!(DWC_READ_REG32(c_mphi_regs.ctrl) & (1 << 17))) -- ; -- DWC_WRITE_REG32(c_mphi_regs.ctrl, (1<<31)); -- mphi_int_count = 0; -+ /* Clear the MPHI interrupt */ -+ DWC_WRITE_REG32(c_mphi_regs.intstat, (1<<16)); -+ if (mphi_int_count >= 60) -+ { -+ DWC_WRITE_REG32(c_mphi_regs.ctrl, ((1<<31) + (1<<16))); -+ while(!(DWC_READ_REG32(c_mphi_regs.ctrl) & (1 << 17))) -+ ; -+ DWC_WRITE_REG32(c_mphi_regs.ctrl, (1<<31)); -+ mphi_int_count = 0; -+ } -+ int_done++; - } -- int_done++; -+ -+ // Unmask handled interrupts -+ FIQ_WRITE(dwc_regs_base + 0x18, gintmsk.d32); -+ //DWC_MODIFY_REG32((uint32_t *)IO_ADDRESS(USB_BASE + 0x8), 0 , 1); -+ -+ local_fiq_enable(); -+ - if((jiffies / HZ) > last_time) - { - /* Once a second output the fiq and irq numbers, useful for debug */ - last_time = jiffies / HZ; - DWC_DEBUGPL(DBG_USER, "int_done = %d fiq_done = %d\n", int_done, fiq_done); - } -- -- /* Re-Enable FIQ interrupt from USB peripheral */ -- DWC_MODIFY_REG32((uint32_t *)IO_ADDRESS(USB_BASE + 0x8), 0 , 1); - } - - DWC_SPINUNLOCK(dwc_otg_hcd->lock); -@@ -294,13 +662,12 @@ static inline void track_missed_sofs(uint16_t curr_frame_number) - * (micro)frame. Periodic transactions may be queued to the controller for the - * next (micro)frame. - */ --int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * hcd, int32_t work_expected) -+int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * hcd) - { - hfnum_data_t hfnum; - dwc_list_link_t *qh_entry; - dwc_otg_qh_t *qh; - dwc_otg_transaction_type_e tr_type; -- gintsts_data_t gintsts = {.d32 = 0 }; - int did_something = 0; - int32_t next_sched_frame = -1; - -@@ -326,6 +693,7 @@ int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * hcd, int32_t work_expected) - qh = DWC_LIST_ENTRY(qh_entry, dwc_otg_qh_t, qh_list_entry); - qh_entry = qh_entry->next; - if (dwc_frame_num_le(qh->sched_frame, hcd->frame_number)) { -+ - /* - * Move QH to the ready list to be executed next - * (micro)frame. -@@ -351,15 +719,10 @@ int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * hcd, int32_t work_expected) - dwc_otg_hcd_queue_transactions(hcd, tr_type); - did_something = 1; - } -- if(work_expected && !did_something) -- DWC_DEBUGPL(DBG_USER, "Nothing to do !! frame = %x, g_next_sched_frame = %x\n", (int) hfnum.b.frnum, g_next_sched_frame); -- if(!work_expected && did_something) -- DWC_DEBUGPL(DBG_USER, "Unexpected work done !! frame = %x, g_next_sched_frame = %x\n", (int) hfnum.b.frnum, g_next_sched_frame); -- - - /* Clear interrupt */ -- gintsts.b.sofintr = 1; -- DWC_WRITE_REG32(&hcd->core_if->core_global_regs->gintsts, gintsts.d32); -+ //gintsts.b.sofintr = 1; -+ //DWC_WRITE_REG32(&hcd->core_if->core_global_regs->gintsts, gintsts.d32); - - return 1; - } -@@ -643,6 +1006,15 @@ int32_t dwc_otg_hcd_handle_hc_intr(dwc_otg_hcd_t * dwc_otg_hcd) - - haint.d32 = dwc_otg_read_host_all_channels_intr(dwc_otg_hcd->core_if); - -+ // Overwrite with saved interrupts from fiq handler -+ if(fiq_split_enable) -+ { -+ local_fiq_disable(); -+ haint.d32 = haint_saved.d32; -+ haint_saved.d32 = 0; -+ local_fiq_enable(); -+ } -+ - for (i = 0; i < dwc_otg_hcd->core_if->core_params->host_channels; i++) { - if (haint.b2.chint & (1 << i)) { - retval |= dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd, i); -@@ -683,7 +1055,10 @@ static uint32_t get_actual_xfer_length(dwc_hc_t * hc, - *short_read = (hctsiz.b.xfersize != 0); - } - } else if (hc->qh->do_split) { -- length = qtd->ssplit_out_xfer_count; -+ if(fiq_split_enable) -+ length = split_out_xfersize[hc->hc_num]; -+ else -+ length = qtd->ssplit_out_xfer_count; - } else { - length = hc->xfer_len; - } -@@ -727,7 +1102,6 @@ static int update_urb_state_xfer_comp(dwc_hc_t * hc, - DWC_OTG_HC_XFER_COMPLETE, - &short_read); - -- - /* non DWORD-aligned buffer case handling. */ - if (hc->align_buff && xfer_length && hc->ep_is_in) { - dwc_memcpy(urb->buf + urb->actual_length, hc->qh->dw_align_buf, -@@ -930,6 +1304,9 @@ static void release_channel(dwc_otg_hcd_t * hcd, - int free_qtd; - dwc_irqflags_t flags; - dwc_spinlock_t *channel_lock = hcd->channel_lock; -+#ifdef FIQ_DEBUG -+ int endp = qtd->urb ? qtd->urb->pipe_info.ep_num : 0; -+#endif - - DWC_DEBUGPL(DBG_HCDV, " %s: channel %d, halt_status %d, xfer_len %d\n", - __func__, hc->hc_num, halt_status, hc->xfer_len); -@@ -1008,9 +1385,24 @@ cleanup: - - DWC_SPINLOCK_IRQSAVE(channel_lock, &flags); - hcd->available_host_channels++; -+ fiq_print(FIQDBG_PORTHUB, "AHC = %d ", hcd->available_host_channels); - DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags); - } - -+ if(fiq_split_enable && hc->do_split) -+ { -+ if(!(hcd->hub_port[hc->hub_addr] & (1 << hc->port_addr))) -+ { -+ fiq_print(FIQDBG_ERR, "PRTNOTAL"); -+ //BUG(); -+ } -+ -+ hcd->hub_port[hc->hub_addr] &= ~(1 << hc->port_addr); -+ hcd->hub_port_alloc[hc->hub_addr * 16 + hc->port_addr] = -1; -+ -+ fiq_print(FIQDBG_PORTHUB, "H%dP%d:RR%d", hc->hub_addr, hc->port_addr, endp); -+ } -+ - /* Try to queue more transfers now that there's a free channel. */ - tr_type = dwc_otg_hcd_select_transactions(hcd); - if (tr_type != DWC_OTG_TRANSACTION_NONE) { -@@ -1633,8 +2025,10 @@ static int32_t handle_hc_nyet_intr(dwc_otg_hcd_t * hcd, - hc->ep_type == DWC_OTG_EP_TYPE_ISOC) { - int frnum = dwc_otg_hcd_get_frame_number(hcd); - -+ // With the FIQ running we only ever see the failed NYET - if (dwc_full_frame_num(frnum) != -- dwc_full_frame_num(hc->qh->sched_frame)) { -+ dwc_full_frame_num(hc->qh->sched_frame) || -+ fiq_split_enable) { - /* - * No longer in the same full speed frame. - * Treat this as a transaction error. -@@ -2012,10 +2406,10 @@ static inline int halt_status_ok(dwc_otg_hcd_t * hcd, - static void handle_hc_chhltd_intr_dma(dwc_otg_hcd_t * hcd, - dwc_hc_t * hc, - dwc_otg_hc_regs_t * hc_regs, -- dwc_otg_qtd_t * qtd) -+ dwc_otg_qtd_t * qtd, -+ hcint_data_t hcint, -+ hcintmsk_data_t hcintmsk) - { -- hcint_data_t hcint; -- hcintmsk_data_t hcintmsk; - int out_nak_enh = 0; - - /* For core with OUT NAK enhancement, the flow for high- -@@ -2047,8 +2441,11 @@ static void handle_hc_chhltd_intr_dma(dwc_otg_hcd_t * hcd, - } - - /* Read the HCINTn register to determine the cause for the halt. */ -- hcint.d32 = DWC_READ_REG32(&hc_regs->hcint); -- hcintmsk.d32 = DWC_READ_REG32(&hc_regs->hcintmsk); -+ if(!fiq_split_enable) -+ { -+ hcint.d32 = DWC_READ_REG32(&hc_regs->hcint); -+ hcintmsk.d32 = DWC_READ_REG32(&hc_regs->hcintmsk); -+ } - - if (hcint.b.xfercomp) { - /** @todo This is here because of a possible hardware bug. Spec -@@ -2161,13 +2558,15 @@ static void handle_hc_chhltd_intr_dma(dwc_otg_hcd_t * hcd, - static int32_t handle_hc_chhltd_intr(dwc_otg_hcd_t * hcd, - dwc_hc_t * hc, - dwc_otg_hc_regs_t * hc_regs, -- dwc_otg_qtd_t * qtd) -+ dwc_otg_qtd_t * qtd, -+ hcint_data_t hcint, -+ hcintmsk_data_t hcintmsk) - { - DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: " - "Channel Halted--\n", hc->hc_num); - - if (hcd->core_if->dma_enable) { -- handle_hc_chhltd_intr_dma(hcd, hc, hc_regs, qtd); -+ handle_hc_chhltd_intr_dma(hcd, hc, hc_regs, qtd, hcint, hcintmsk); - } else { - #ifdef DEBUG - if (!halt_status_ok(hcd, hc, hc_regs, qtd)) { -@@ -2184,7 +2583,7 @@ static int32_t handle_hc_chhltd_intr(dwc_otg_hcd_t * hcd, - int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd, uint32_t num) - { - int retval = 0; -- hcint_data_t hcint; -+ hcint_data_t hcint, hcint_orig; - hcintmsk_data_t hcintmsk; - dwc_hc_t *hc; - dwc_otg_hc_regs_t *hc_regs; -@@ -2197,12 +2596,23 @@ int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd, uint32_t num) - qtd = DWC_CIRCLEQ_FIRST(&hc->qh->qtd_list); - - hcint.d32 = DWC_READ_REG32(&hc_regs->hcint); -+ hcint_orig = hcint; - hcintmsk.d32 = DWC_READ_REG32(&hc_regs->hcintmsk); - DWC_DEBUGPL(DBG_HCDV, - " hcint 0x%08x, hcintmsk 0x%08x, hcint&hcintmsk 0x%08x\n", - hcint.d32, hcintmsk.d32, (hcint.d32 & hcintmsk.d32)); - hcint.d32 = hcint.d32 & hcintmsk.d32; - -+ if(fiq_split_enable) -+ { -+ // replace with the saved interrupts from the fiq handler -+ local_fiq_disable(); -+ hcint_orig.d32 = hcint_saved[num].d32; -+ hcint.d32 = hcint_orig.d32 & hcintmsk_saved[num].d32; -+ hcint_saved[num].d32 = 0; -+ local_fiq_enable(); -+ } -+ - if (!dwc_otg_hcd->core_if->dma_enable) { - if (hcint.b.chhltd && hcint.d32 != 0x2) { - hcint.b.chhltd = 0; -@@ -2220,7 +2630,7 @@ int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd, uint32_t num) - hcint.b.nyet = 0; - } - if (hcint.b.chhltd) { -- retval |= handle_hc_chhltd_intr(dwc_otg_hcd, hc, hc_regs, qtd); -+ retval |= handle_hc_chhltd_intr(dwc_otg_hcd, hc, hc_regs, qtd, hcint_orig, hcintmsk_saved[num]); - } - if (hcint.b.ahberr) { - retval |= handle_hc_ahberr_intr(dwc_otg_hcd, hc, hc_regs, qtd); -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c -index fef557d..0d6f5f4 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c -@@ -392,7 +392,11 @@ static struct dwc_otg_hcd_function_ops hcd_fops = { - static struct fiq_handler fh = { - .name = "usb_fiq", - }; --static uint8_t fiqStack[1024]; -+struct fiq_stack_s { -+ int magic1; -+ uint8_t stack[2048]; -+ int magic2; -+} fiq_stack; - - extern mphi_regs_t c_mphi_regs; - /** -@@ -434,9 +438,11 @@ int hcd_init(dwc_bus_dev_t *_dev) - memset(®s,0,sizeof(regs)); - regs.ARM_r8 = (long)dwc_otg_hcd_handle_fiq; - regs.ARM_r9 = (long)0; -- regs.ARM_sp = (long)fiqStack + sizeof(fiqStack) - 4; -+ regs.ARM_sp = (long)fiq_stack.stack + sizeof(fiq_stack.stack) - 4; - set_fiq_regs(®s); -- } -+ fiq_stack.magic1 = 0xdeadbeef; -+ fiq_stack.magic2 = 0xaa995566; -+ } - - /* - * Allocate memory for the base HCD plus the DWC OTG HCD. -@@ -459,6 +465,8 @@ int hcd_init(dwc_bus_dev_t *_dev) - - if (fiq_fix_enable) - { -+ volatile extern void *dwc_regs_base; -+ - //Set the mphi periph to the required registers - c_mphi_regs.base = otg_dev->os_dep.mphi_base; - c_mphi_regs.ctrl = otg_dev->os_dep.mphi_base + 0x4c; -@@ -466,6 +474,8 @@ int hcd_init(dwc_bus_dev_t *_dev) - c_mphi_regs.outddb = otg_dev->os_dep.mphi_base + 0x2c; - c_mphi_regs.intstat = otg_dev->os_dep.mphi_base + 0x50; - -+ dwc_regs_base = otg_dev->os_dep.base; -+ - //Enable mphi peripheral - writel((1<<31),c_mphi_regs.ctrl); - #ifdef DEBUG -@@ -839,6 +849,8 @@ static int dwc_otg_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) - usb_hcd_unlink_urb_from_ep(hcd, urb); - #endif - DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags); -+ -+ - #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) - usb_hcd_giveback_urb(hcd, urb); - #else -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c -index b3e6e52..8125307 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c -@@ -41,6 +41,7 @@ - - #include "dwc_otg_hcd.h" - #include "dwc_otg_regs.h" -+#include "dwc_otg_mphi_fix.h" - - extern bool microframe_schedule; - -@@ -191,6 +192,7 @@ void qh_init(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, dwc_otg_hcd_urb_t * urb) - dwc_otg_hcd_get_ep_num(&urb->pipe_info), hub_addr, - hub_port); - qh->do_split = 1; -+ qh->skip_count = 0; - } - - if (qh->ep_type == UE_INTERRUPT || qh->ep_type == UE_ISOCHRONOUS) { -@@ -737,6 +739,9 @@ void dwc_otg_hcd_qh_remove(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) - hcd->non_periodic_qh_ptr->next; - } - DWC_LIST_REMOVE_INIT(&qh->qh_list_entry); -+ -+ // If we've removed the last non-periodic entry then there are none left! -+ g_np_count = g_np_sent; - } else { - deschedule_periodic(hcd, qh); - hcd->periodic_qh_count--; -@@ -766,21 +771,21 @@ void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, - { - if (dwc_qh_is_non_per(qh)) { - -- dwc_otg_qh_t *qh_tmp; -- dwc_list_link_t *qh_list; -- DWC_LIST_FOREACH(qh_list, &hcd->non_periodic_sched_inactive) -- { -- qh_tmp = DWC_LIST_ENTRY(qh_list, struct dwc_otg_qh, qh_list_entry); -- if(qh_tmp == qh) -+ dwc_otg_qh_t *qh_tmp; -+ dwc_list_link_t *qh_list; -+ DWC_LIST_FOREACH(qh_list, &hcd->non_periodic_sched_inactive) - { -- /* -- * FIQ is being disabled because this one nevers gets a np_count increment -- * This is still not absolutely correct, but it should fix itself with -- * just an unnecessary extra interrupt -- */ -- g_np_sent = g_np_count; -+ qh_tmp = DWC_LIST_ENTRY(qh_list, struct dwc_otg_qh, qh_list_entry); -+ if(qh_tmp == qh) -+ { -+ /* -+ * FIQ is being disabled because this one nevers gets a np_count increment -+ * This is still not absolutely correct, but it should fix itself with -+ * just an unnecessary extra interrupt -+ */ -+ g_np_sent = g_np_count; -+ } - } -- } - - - dwc_otg_hcd_qh_remove(hcd, qh); -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.h b/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.h -index 22f28e1..ca17379 100755 ---- a/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.h -+++ b/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.h -@@ -1,10 +1,7 @@ - #ifndef __DWC_OTG_MPHI_FIX_H__ - #define __DWC_OTG_MPHI_FIX_H__ -- --#define FIQ_WRITE_IO_ADDRESS(_addr_,_data_) *(volatile uint32_t *) IO_ADDRESS(_addr_) = _data_ --#define FIQ_READ_IO_ADDRESS(_addr_) *(volatile uint32_t *) IO_ADDRESS(_addr_) --#define FIQ_MODIFY_IO_ADDRESS(_addr_,_clear_,_set_) FIQ_WRITE_IO_ADDRESS(_addr_ , (FIQ_READ_IO_ADDRESS(_addr_)&~_clear_)|_set_) --#define FIQ_WRITE(_addr_,_data_) *(volatile uint32_t *) _addr_ = _data_ -+#define FIQ_WRITE(_addr_,_data_) (*(volatile uint32_t *) (_addr_) = (_data_)) -+#define FIQ_READ(_addr_) (*(volatile uint32_t *) (_addr_)) - - typedef struct { - volatile void* base; -@@ -12,13 +9,13 @@ typedef struct { - volatile void* outdda; - volatile void* outddb; - volatile void* intstat; --} mphi_regs_t; -+} mphi_regs_t; - - void dwc_debug_print_core_int_reg(gintsts_data_t gintsts, const char* function_name); - void dwc_debug_core_int_mask(gintsts_data_t gintmsk, const char* function_name); - void dwc_debug_otg_int(gotgint_data_t gotgint, const char* function_name); - -- -+extern gintsts_data_t gintsts_saved; - - #ifdef DEBUG - #define DWC_DBG_PRINT_CORE_INT(_arg_) dwc_debug_print_core_int_reg(_arg_,__func__) -@@ -30,7 +27,22 @@ void dwc_debug_otg_int(gotgint_data_t gotgint, const char* function_name); - #define DWC_DBG_PRINT_CORE_INT_MASK(_arg_) - #define DWC_DBG_PRINT_OTG_INT(_arg_) - -+#endif -+ -+typedef enum { -+ FIQDBG_SCHED = (1 << 0), -+ FIQDBG_INT = (1 << 1), -+ FIQDBG_ERR = (1 << 2), -+ FIQDBG_PORTHUB = (1 << 3), -+} FIQDBG_T; - -+void _fiq_print(FIQDBG_T dbg_lvl, char *fmt, ...); -+#ifdef FIQ_DEBUG -+#define fiq_print _fiq_print -+#else -+#define fiq_print(x, y, ...) - #endif - -+extern bool fiq_fix_enable, nak_holdoff_enable, fiq_split_enable; -+ - #endif -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c -index 27061d3..9720937 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c -@@ -4276,7 +4276,7 @@ do { \ - && (pcd->ep0state == EP0_OUT_DATA_PHASE)) - status.d32 = core_if->dev_if->out_desc_addr->status.d32; - if (pcd->ep0state == EP0_OUT_STATUS_PHASE) -- status.d32 = status.d32 = core_if->dev_if-> -+ status.d32 = core_if->dev_if-> - out_desc_addr->status.d32; - - if (status.b.sr) { --- -1.9.1 - -- cgit v1.2.3