From 91517efe9659881028ad3d5d121ec7dc7913097b Mon Sep 17 00:00:00 2001 From: ckkim Date: Wed, 28 Oct 2015 14:45:23 +0900 Subject: [PATCH] Revert "C1: USB FIQ driver (Not ready)" --- .../dts/amlogic/meson8_k200b_1G_emmc_sdhc.dtd | 2 - .../dts/amlogic/meson8_k200b_1G_emmc_sdio.dtd | 2 - arch/arm/boot/dts/amlogic/meson8b_m201_1G.dtd | 2 - arch/arm/boot/dts/meson8b_odroidc.dts | 2 - arch/arm/configs/odroidc_defconfig | 1 - arch/arm/include/asm/fiq.h | 2 - arch/arm/include/asm/hardware/gic.h | 1 - arch/arm/kernel/fiq.c | 9 - arch/arm/kernel/fiqasm.S | 21 - arch/arm/mach-meson8/Kconfig | 6 - arch/arm/mach-meson8/include/mach/irqs.h | 2 +- arch/arm/mach-meson8b/Kconfig | 7 - arch/arm/mach-meson8b/include/mach/irqs.h | 2 +- arch/arm/plat-meson/gic-irq.c | 22 +- drivers/amlogic/usb/dwc_otg/310/Makefile | 2 - .../310/common_port/dwc_common_linux.c | 11 - .../usb/dwc_otg/310/common_port/dwc_list.h | 14 +- .../usb/dwc_otg/310/common_port/dwc_os.h | 2 - drivers/amlogic/usb/dwc_otg/310/dwc_otg_adp.c | 0 .../amlogic/usb/dwc_otg/310/dwc_otg_attr.c | 0 drivers/amlogic/usb/dwc_otg/310/dwc_otg_cil.c | 6 +- drivers/amlogic/usb/dwc_otg/310/dwc_otg_cil.h | 5 +- .../usb/dwc_otg/310/dwc_otg_cil_intr.c | 49 +- .../amlogic/usb/dwc_otg/310/dwc_otg_core_if.h | 0 .../amlogic/usb/dwc_otg/310/dwc_otg_driver.c | 74 +- .../amlogic/usb/dwc_otg/310/dwc_otg_driver.h | 1 - .../amlogic/usb/dwc_otg/310/dwc_otg_fiq_fsm.c | 1348 ----------------- .../amlogic/usb/dwc_otg/310/dwc_otg_fiq_fsm.h | 354 ----- .../usb/dwc_otg/310/dwc_otg_fiq_stub.S | 81 - drivers/amlogic/usb/dwc_otg/310/dwc_otg_hcd.c | 1036 +++---------- drivers/amlogic/usb/dwc_otg/310/dwc_otg_hcd.h | 92 +- .../usb/dwc_otg/310/dwc_otg_hcd_ddma.c | 14 +- .../amlogic/usb/dwc_otg/310/dwc_otg_hcd_if.h | 7 +- .../usb/dwc_otg/310/dwc_otg_hcd_intr.c | 710 +-------- .../usb/dwc_otg/310/dwc_otg_hcd_linux.c | 369 +++-- .../usb/dwc_otg/310/dwc_otg_hcd_queue.c | 242 +-- drivers/amlogic/usb/dwc_otg/310/dwc_otg_pcd.c | 0 drivers/amlogic/usb/dwc_otg/310/dwc_otg_pcd.h | 0 .../amlogic/usb/dwc_otg/310/dwc_otg_pcd_if.h | 0 .../usb/dwc_otg/310/dwc_otg_pcd_intr.c | 0 .../usb/dwc_otg/310/dwc_otg_pcd_linux.c | 7 +- .../amlogic/usb/dwc_otg/310/dwc_otg_regs.h | 0 drivers/irqchip/irq-gic.c | 112 +- kernel/irq/chip.c | 4 +- 44 files changed, 559 insertions(+), 4062 deletions(-) mode change 100755 => 100644 arch/arm/include/asm/fiq.h mode change 100755 => 100644 arch/arm/kernel/fiq.c mode change 100755 => 100644 arch/arm/plat-meson/gic-irq.c mode change 100755 => 100644 drivers/amlogic/usb/dwc_otg/310/dwc_otg_adp.c mode change 100755 => 100644 drivers/amlogic/usb/dwc_otg/310/dwc_otg_attr.c mode change 100755 => 100644 drivers/amlogic/usb/dwc_otg/310/dwc_otg_cil.c mode change 100755 => 100644 drivers/amlogic/usb/dwc_otg/310/dwc_otg_cil.h mode change 100755 => 100644 drivers/amlogic/usb/dwc_otg/310/dwc_otg_cil_intr.c mode change 100755 => 100644 drivers/amlogic/usb/dwc_otg/310/dwc_otg_core_if.h mode change 100755 => 100644 drivers/amlogic/usb/dwc_otg/310/dwc_otg_driver.h delete mode 100644 drivers/amlogic/usb/dwc_otg/310/dwc_otg_fiq_fsm.c delete mode 100644 drivers/amlogic/usb/dwc_otg/310/dwc_otg_fiq_fsm.h delete mode 100644 drivers/amlogic/usb/dwc_otg/310/dwc_otg_fiq_stub.S mode change 100755 => 100644 drivers/amlogic/usb/dwc_otg/310/dwc_otg_hcd.c mode change 100755 => 100644 drivers/amlogic/usb/dwc_otg/310/dwc_otg_hcd.h mode change 100755 => 100644 drivers/amlogic/usb/dwc_otg/310/dwc_otg_hcd_if.h mode change 100755 => 100644 drivers/amlogic/usb/dwc_otg/310/dwc_otg_hcd_intr.c mode change 100755 => 100644 drivers/amlogic/usb/dwc_otg/310/dwc_otg_hcd_queue.c mode change 100755 => 100644 drivers/amlogic/usb/dwc_otg/310/dwc_otg_pcd.c mode change 100755 => 100644 drivers/amlogic/usb/dwc_otg/310/dwc_otg_pcd.h mode change 100755 => 100644 drivers/amlogic/usb/dwc_otg/310/dwc_otg_pcd_if.h mode change 100755 => 100644 drivers/amlogic/usb/dwc_otg/310/dwc_otg_pcd_intr.c mode change 100755 => 100644 drivers/amlogic/usb/dwc_otg/310/dwc_otg_regs.h mode change 100755 => 100644 kernel/irq/chip.c diff --git a/arch/arm/boot/dts/amlogic/meson8_k200b_1G_emmc_sdhc.dtd b/arch/arm/boot/dts/amlogic/meson8_k200b_1G_emmc_sdhc.dtd index c85e0d810eb8..5548c43ca1d1 100755 --- a/arch/arm/boot/dts/amlogic/meson8_k200b_1G_emmc_sdhc.dtd +++ b/arch/arm/boot/dts/amlogic/meson8_k200b_1G_emmc_sdhc.dtd @@ -110,7 +110,6 @@ void root_func(){ reg = <0xc4301000 0x1000 0xc4300100 0x0100>; interrupt-controller; - gic_fiq_enable; #interrupt-cells = <3>; #address-cells = <0>; }; @@ -876,7 +875,6 @@ sdio{ port-config = <0>; /** 0: default */ port-dma = <0>; /** 0: default, 1: single, 2: incr, 3: incr4, 4: incr8, 5: incr16, 6: disable*/ port-id-mode = <1>; /** 0: hardware, 1: sw_host, 2: sw_slave*/ - fiq_use = <1>; /**0:no use 1: use**/ status = "okay"; }; diff --git a/arch/arm/boot/dts/amlogic/meson8_k200b_1G_emmc_sdio.dtd b/arch/arm/boot/dts/amlogic/meson8_k200b_1G_emmc_sdio.dtd index 3ce2ddb008a9..ca339c36d9cc 100755 --- a/arch/arm/boot/dts/amlogic/meson8_k200b_1G_emmc_sdio.dtd +++ b/arch/arm/boot/dts/amlogic/meson8_k200b_1G_emmc_sdio.dtd @@ -110,7 +110,6 @@ void root_func(){ reg = <0xc4301000 0x1000 0xc4300100 0x0100>; interrupt-controller; - gic_fiq_enable; #interrupt-cells = <3>; #address-cells = <0>; }; @@ -864,7 +863,6 @@ sdio{ port-config = <0>; /** 0: default */ port-dma = <0>; /** 0: default, 1: single, 2: incr, 3: incr4, 4: incr8, 5: incr16, 6: disable*/ port-id-mode = <1>; /** 0: hardware, 1: sw_host, 2: sw_slave*/ - fiq_use = <1>; /**0:no use 1: use**/ status = "okay"; }; diff --git a/arch/arm/boot/dts/amlogic/meson8b_m201_1G.dtd b/arch/arm/boot/dts/amlogic/meson8b_m201_1G.dtd index a753c0fd2c67..b5aef6f3b052 100755 --- a/arch/arm/boot/dts/amlogic/meson8b_m201_1G.dtd +++ b/arch/arm/boot/dts/amlogic/meson8b_m201_1G.dtd @@ -99,7 +99,6 @@ void root_func(){ reg = <0xc4301000 0x1000 0xc4300100 0x0100>; interrupt-controller; - gic_fiq_enable; #interrupt-cells = <3>; #address-cells = <0>; }; @@ -853,7 +852,6 @@ void root_func(){ port-config = <0>; /** 0: default */ port-dma = <0>; /** 0: default, 1: single, 2: incr, 3: incr4, 4: incr8, 5: incr16, 6: disable*/ port-id-mode = <1>; /** 0: hardware, 1: sw_host, 2: sw_slave*/ - fiq_use = <1>; status = "okay"; }; diff --git a/arch/arm/boot/dts/meson8b_odroidc.dts b/arch/arm/boot/dts/meson8b_odroidc.dts index a8bbfb19f20d..3bef0b258971 100755 --- a/arch/arm/boot/dts/meson8b_odroidc.dts +++ b/arch/arm/boot/dts/meson8b_odroidc.dts @@ -69,7 +69,6 @@ reg = <0xc4301000 0x1000 0xc4300100 0x0100>; interrupt-controller; - gic_fiq_enable; #interrupt-cells = <3>; #address-cells = <0>; }; @@ -366,7 +365,6 @@ port-dma = <0>; /** 0: default, 1: single, 2: incr, 3: incr4, 4: incr8, 5: incr16, 6: disable*/ port-id-mode = <1>; /** 0: hardware, 1: sw_host, 2: sw_slave*/ gpio-hub-rst = "GPIOAO_4"; - fiq_use = <1>; status = "okay"; }; diff --git a/arch/arm/configs/odroidc_defconfig b/arch/arm/configs/odroidc_defconfig index e7b44a260797..904e7c9cd04e 100644 --- a/arch/arm/configs/odroidc_defconfig +++ b/arch/arm/configs/odroidc_defconfig @@ -526,7 +526,6 @@ CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y # CONFIG_ARM_KIRKWOOD_CPUFREQ is not set CONFIG_AMLOGIC_MESON_CPUFREQ=y CONFIG_FIX_SYSPLL=y -CONFIG_MESON_GIC_FIQ=y # CONFIG_CPU_IDLE is not set # CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h old mode 100755 new mode 100644 index a002ae649333..d493d0b742a1 --- a/arch/arm/include/asm/fiq.h +++ b/arch/arm/include/asm/fiq.h @@ -38,12 +38,10 @@ extern void release_fiq(struct fiq_handler *f); extern void set_fiq_handler(void *start, unsigned int length); extern void enable_fiq(int fiq); extern void disable_fiq(int fiq); -extern int get_fiq_index(void); /* helpers defined in fiqasm.S: */ extern void __set_fiq_regs(unsigned long const *regs); extern void __get_fiq_regs(unsigned long *regs); -extern void __FIQ_Branch(unsigned long *regs); static inline void set_fiq_regs(struct pt_regs const *regs) { diff --git a/arch/arm/include/asm/hardware/gic.h b/arch/arm/include/asm/hardware/gic.h index 184663acc175..4b1ce6cd477f 100644 --- a/arch/arm/include/asm/hardware/gic.h +++ b/arch/arm/include/asm/hardware/gic.h @@ -22,7 +22,6 @@ #define GIC_DIST_CTRL 0x000 #define GIC_DIST_CTR 0x004 -#define GIC_DIST_IGROUP 0x080 #define GIC_DIST_ENABLE_SET 0x100 #define GIC_DIST_ENABLE_CLEAR 0x180 #define GIC_DIST_PENDING_SET 0x200 diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c old mode 100755 new mode 100644 index ede5c004ae64..25442f451148 --- a/arch/arm/kernel/fiq.c +++ b/arch/arm/kernel/fiq.c @@ -53,7 +53,6 @@ }) static unsigned long no_fiq_insn; -static int fiqno = 0x4000; /* Default reacquire function * - we always relinquish FIQ control @@ -135,19 +134,12 @@ static int fiq_start; void enable_fiq(int fiq) { - fiqno = fiq; enable_irq(fiq + fiq_start); } void disable_fiq(int fiq) { disable_irq(fiq + fiq_start); - fiqno = 0x4000; -} - -int get_fiq_index(void) -{ - return fiqno; } EXPORT_SYMBOL(set_fiq_handler); @@ -157,7 +149,6 @@ EXPORT_SYMBOL(claim_fiq); EXPORT_SYMBOL(release_fiq); EXPORT_SYMBOL(enable_fiq); EXPORT_SYMBOL(disable_fiq); -EXPORT_SYMBOL(get_fiq_index); void __init init_FIQ(int start) { diff --git a/arch/arm/kernel/fiqasm.S b/arch/arm/kernel/fiqasm.S index b302445c2a1d..207f9d652010 100644 --- a/arch/arm/kernel/fiqasm.S +++ b/arch/arm/kernel/fiqasm.S @@ -25,9 +25,6 @@ ENTRY(__set_fiq_regs) mov r2, #PSR_I_BIT | PSR_F_BIT | FIQ_MODE mrs r1, cpsr -@@@@@@@@@@@@@@@ hack: enable the fiq here to keep usb driver happy - and r1, #~PSR_F_BIT -@@@@@@@@@@@@@@@ endhack: (need to find better place for this to happen) msr cpsr_c, r2 @ select FIQ mode mov r0, r0 @ avoid hazard prior to ARMv4 ldmia r0!, {r8 - r12} @@ -50,21 +47,3 @@ ENTRY(__get_fiq_regs) mov r0, r0 @ avoid hazard prior to ARMv4 mov pc, lr ENDPROC(__get_fiq_regs) - -ENTRY(__FIQ_Branch) - mov pc, r8 -ENDPROC(__FIQ_Branch) - -ENTRY(__fiq_ll_setup) - stmdb sp!, {r4} - mrs r4, cpsr -@ and r4, #~PSR_F_BIT - msr cpsr_c, #(FIQ_MODE | PSR_I_BIT | PSR_F_BIT) - mov r8, r0 - mov r9, r1 - mov fp, r2 - mov sp, r3 - msr cpsr_c, r4 - ldmia sp!, {r4} - mov pc, lr -ENDPROC(__fiq_ll_setup) diff --git a/arch/arm/mach-meson8/Kconfig b/arch/arm/mach-meson8/Kconfig index c85f2a7ca5ac..b397def38435 100755 --- a/arch/arm/mach-meson8/Kconfig +++ b/arch/arm/mach-meson8/Kconfig @@ -70,10 +70,4 @@ config GPIO_TEST help support gpio group test -config MESON_GIC_FIQ - bool "MESON support GIC FIQ" - default n - depends on FIQ - help - support GIC FIQ endif # ARCH_MESON8 diff --git a/arch/arm/mach-meson8/include/mach/irqs.h b/arch/arm/mach-meson8/include/mach/irqs.h index ab5073d8cee3..d24ae779ca0a 100644 --- a/arch/arm/mach-meson8/include/mach/irqs.h +++ b/arch/arm/mach-meson8/include/mach/irqs.h @@ -193,7 +193,7 @@ /* All interrupts are FIQ capable */ -#define FIQ_START 0 +#define FIQ_START AM_IRQ0(0) extern void request_fiq(unsigned fiq, void (*isr)(void)); extern void free_fiq(unsigned fiq, void (*isr)(void)); diff --git a/arch/arm/mach-meson8b/Kconfig b/arch/arm/mach-meson8b/Kconfig index e9dcd3952b1c..cb0ef5d1ca6b 100644 --- a/arch/arm/mach-meson8b/Kconfig +++ b/arch/arm/mach-meson8b/Kconfig @@ -24,13 +24,6 @@ config MESON_TRUSTZONE default n help Enable ARM Trustzone secure extension - -config MESON_GIC_FIQ - bool "MESON support GIC FIQ" - default n - depends on FIQ - help - support GIC FIQ endif # ARCH_MESON8 diff --git a/arch/arm/mach-meson8b/include/mach/irqs.h b/arch/arm/mach-meson8b/include/mach/irqs.h index 2b9ad6c4eb7f..f552c922a94d 100644 --- a/arch/arm/mach-meson8b/include/mach/irqs.h +++ b/arch/arm/mach-meson8b/include/mach/irqs.h @@ -193,7 +193,7 @@ /* All interrupts are FIQ capable */ -#define FIQ_START 0 +#define FIQ_START AM_IRQ0(0) extern void request_fiq(unsigned fiq, void (*isr)(void)); extern void free_fiq(unsigned fiq, void (*isr)(void)); diff --git a/arch/arm/plat-meson/gic-irq.c b/arch/arm/plat-meson/gic-irq.c old mode 100755 new mode 100644 index 7e50c9564ffb..0c47280f30cd --- a/arch/arm/plat-meson/gic-irq.c +++ b/arch/arm/plat-meson/gic-irq.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #ifdef CONFIG_OF @@ -49,20 +48,19 @@ static void meson_gic_unmask(struct irq_data *data) * Set irq to edge rising and proi to low */ uint32_t dist_base=(uint32_t)(IO_PERIPH_BASE+0x1000); - int edge = 0x3;//edge - int irq=data->irq; + int edge = 0x3;//edge + + int irq=data->irq; if(irq<32) return; - if(irq >= FIQ_START) - irq -= FIQ_START; /** * Deal with IRQ type: IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH */ if(data->state_use_accessors & IRQ_TYPE_LEVEL_MASK) edge = 0x1;//level - if((irq == 62)||(irq == 63)) + if((irq == 62)||(irq == 63)) edge = 0x1;//level /** @@ -72,15 +70,10 @@ static void meson_gic_unmask(struct irq_data *data) /** * Set prority */ + aml_set_reg32_bits(dist_base+GIC_DIST_PRI + (irq / 4)* 4,0xff,(irq%4)*8,irq_level); - if(data->irq == get_fiq_index()) - aml_set_reg32_bits(dist_base + GIC_DIST_IGROUP + (irq / 32) * 4, 0, (irq%32), 1); - else - aml_set_reg32_bits(dist_base + GIC_DIST_IGROUP + (irq / 32) * 4, 1, (irq%32), 1); - } - #ifdef CONFIG_OF static const struct of_device_id mesnon_dt_irq_match[] __initconst = { { .compatible = "arm,cortex-a9-gic", .data = gic_of_init }, @@ -99,8 +92,9 @@ void __init meson_init_gic_irq(void) aml_write_reg32(IO_PERIPH_BASE+0x100 +GIC_CPU_PRIMASK,0xff); -#ifdef CONFIG_MESON_GIC_FIQ - init_FIQ(FIQ_START); +#ifdef CONFIG_MESON_ARM_GIC_FIQ +extern void init_fiq(void) ; + init_fiq(); #endif } diff --git a/drivers/amlogic/usb/dwc_otg/310/Makefile b/drivers/amlogic/usb/dwc_otg/310/Makefile index 4ce707a02e33..5e0e0ae77bc9 100644 --- a/drivers/amlogic/usb/dwc_otg/310/Makefile +++ b/drivers/amlogic/usb/dwc_otg/310/Makefile @@ -25,8 +25,6 @@ $(DWC_OTG_NAME)-objs += dwc_otg_cil.o dwc_otg_cil_intr.o $(DWC_OTG_NAME)-objs += dwc_otg_pcd_linux.o dwc_otg_pcd.o dwc_otg_pcd_intr.o $(DWC_OTG_NAME)-objs += dwc_otg_hcd.o dwc_otg_hcd_linux.o dwc_otg_hcd_intr.o dwc_otg_hcd_queue.o dwc_otg_hcd_ddma.o $(DWC_OTG_NAME)-objs += dwc_otg_adp.o -$(DWC_OTG_NAME)-objs += dwc_otg_fiq_fsm.o -$(DWC_OTG_NAME)-objs += dwc_otg_fiq_stub.o ifneq ($(CFI),) $(DWC_OTG_NAME)-objs += dwc_otg_cfi.o endif diff --git a/drivers/amlogic/usb/dwc_otg/310/common_port/dwc_common_linux.c b/drivers/amlogic/usb/dwc_otg/310/common_port/dwc_common_linux.c index 20c8049550eb..8094cf8bfa9d 100644 --- a/drivers/amlogic/usb/dwc_otg/310/common_port/dwc_common_linux.c +++ b/drivers/amlogic/usb/dwc_otg/310/common_port/dwc_common_linux.c @@ -580,13 +580,7 @@ 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_fiq_enable(); - local_irq_restore(flags); } #if 0 @@ -997,11 +991,6 @@ void DWC_TASK_SCHEDULE(dwc_tasklet_t *task) tasklet_schedule(&task->t); } -void DWC_TASK_HI_SCHEDULE(dwc_tasklet_t *task) -{ - tasklet_hi_schedule(&task->t); -} - /* workqueues - run in process context (can sleep) diff --git a/drivers/amlogic/usb/dwc_otg/310/common_port/dwc_list.h b/drivers/amlogic/usb/dwc_otg/310/common_port/dwc_list.h index 4ce560df0cae..89cc325045fc 100644 --- a/drivers/amlogic/usb/dwc_otg/310/common_port/dwc_list.h +++ b/drivers/amlogic/usb/dwc_otg/310/common_port/dwc_list.h @@ -384,17 +384,17 @@ struct { \ #define DWC_TAILQ_PREV(elm, headname, field) \ (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) #define DWC_TAILQ_EMPTY(head) \ - (DWC_TAILQ_FIRST(head) == DWC_TAILQ_END(head)) + (TAILQ_FIRST(head) == TAILQ_END(head)) #define DWC_TAILQ_FOREACH(var, head, field) \ - for ((var) = DWC_TAILQ_FIRST(head); \ - (var) != DWC_TAILQ_END(head); \ - (var) = DWC_TAILQ_NEXT(var, field)) + for((var) = TAILQ_FIRST(head); \ + (var) != TAILQ_END(head); \ + (var) = TAILQ_NEXT(var, field)) #define DWC_TAILQ_FOREACH_REVERSE(var, head, headname, field) \ - for ((var) = DWC_TAILQ_LAST(head, headname); \ - (var) != DWC_TAILQ_END(head); \ - (var) = DWC_TAILQ_PREV(var, headname, field)) + for((var) = TAILQ_LAST(head, headname); \ + (var) != TAILQ_END(head); \ + (var) = TAILQ_PREV(var, headname, field)) /* * Tail queue functions. diff --git a/drivers/amlogic/usb/dwc_otg/310/common_port/dwc_os.h b/drivers/amlogic/usb/dwc_otg/310/common_port/dwc_os.h index 6ecb016405b3..b9ae38a8046f 100644 --- a/drivers/amlogic/usb/dwc_otg/310/common_port/dwc_os.h +++ b/drivers/amlogic/usb/dwc_otg/310/common_port/dwc_os.h @@ -960,8 +960,6 @@ extern void DWC_TASK_FREE(dwc_tasklet_t *task); extern void DWC_TASK_SCHEDULE(dwc_tasklet_t *task); #define dwc_task_schedule DWC_TASK_SCHEDULE -extern void DWC_TASK_HI_SCHEDULE(dwc_tasklet_t *task); -#define dwc_task_hi_schedule DWC_TASK_HI_SCHEDULE /** @name Timer * diff --git a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_adp.c b/drivers/amlogic/usb/dwc_otg/310/dwc_otg_adp.c old mode 100755 new mode 100644 diff --git a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_attr.c b/drivers/amlogic/usb/dwc_otg/310/dwc_otg_attr.c old mode 100755 new mode 100644 diff --git a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_cil.c b/drivers/amlogic/usb/dwc_otg/310/dwc_otg_cil.c old mode 100755 new mode 100644 index ca1190eaa9c3..c0a8d0f5809a --- a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_cil.c +++ b/drivers/amlogic/usb/dwc_otg/310/dwc_otg_cil.c @@ -2444,9 +2444,9 @@ void dwc_otg_hc_init(dwc_otg_core_if_t * core_if, dwc_hc_t * hc) hcchar.b.epnum = hc->ep_num; hcchar.b.epdir = hc->ep_is_in; hcchar.b.lspddev = (hc->speed == DWC_OTG_EP_SPEED_LOW); - //if((hc->ep_type == DWC_OTG_EP_TYPE_INTR) && hc->do_split && (hc->speed == DWC_OTG_EP_SPEED_FULL)) - // hcchar.b.eptype = DWC_OTG_EP_TYPE_BULK; - //else + if((hc->ep_type == DWC_OTG_EP_TYPE_INTR) && hc->do_split && (hc->speed == DWC_OTG_EP_SPEED_FULL)) + hcchar.b.eptype = DWC_OTG_EP_TYPE_BULK; + else hcchar.b.eptype = hc->ep_type; hcchar.b.mps = hc->max_packet; diff --git a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_cil.h b/drivers/amlogic/usb/dwc_otg/310/dwc_otg_cil.h old mode 100755 new mode 100644 index f2b9d571d859..29462b35a186 --- a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_cil.h +++ b/drivers/amlogic/usb/dwc_otg/310/dwc_otg_cil.h @@ -959,8 +959,6 @@ struct dwc_otg_core_if { /* Host only flag */ int host_only; - int use_fiq_flag; - /** Device mode Periodic Tx FIFO Mask */ uint32_t p_tx_msk; /** Device mode Periodic Tx FIFO Mask */ @@ -1391,8 +1389,7 @@ typedef struct dwc_otg_cil_callbacks { /** Sleep (switch to L0 state) */ int (*sleep) (void *_p); #endif - /** Pointer passed to start() and stop() */ - void *p; + } dwc_otg_cil_callbacks_t; extern void dwc_otg_cil_register_pcd_callbacks(dwc_otg_core_if_t * _core_if, diff --git a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_cil_intr.c b/drivers/amlogic/usb/dwc_otg/310/dwc_otg_cil_intr.c old mode 100755 new mode 100644 index 0a54fd482b93..af20f18d4e35 --- a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_cil_intr.c +++ b/drivers/amlogic/usb/dwc_otg/310/dwc_otg_cil_intr.c @@ -1518,7 +1518,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, gintmsk_data_t *reenable_gintmsk, dwc_otg_hcd_t *hcd) +static inline uint32_t dwc_otg_read_common_intr(dwc_otg_core_if_t * core_if) { gahbcfg_data_t gahbcfg = {.d32 = 0 }; gintsts_data_t gintsts; @@ -1535,45 +1535,26 @@ static inline uint32_t dwc_otg_read_common_intr(dwc_otg_core_if_t * core_if, gin gintmsk_common.b.lpmtranrcvd = 1; #endif gintmsk_common.b.restoredone = 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); - if(fiq_enable && core_if->use_fiq_flag) { - local_fiq_disable(); - /* Pull in the interrupts that the FIQ has masked */ - gintmsk.d32 |= ~(hcd->fiq_state->gintmsk_saved.d32); - gintmsk.d32 |= gintmsk_common.d32; - /* for the upstairs function to reenable - have to read it here in case FIQ triggers again */ - reenable_gintmsk->d32 = gintmsk.d32; - local_fiq_enable(); - } - 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, "common_intr: gintsts=%08x gintmsk=%08x\n", + DWC_DEBUGPL(DBG_ANY, "gintsts=%08x gintmsk=%08x\n", gintsts.d32, gintmsk.d32); } #endif - if (!(fiq_enable&&core_if->use_fiq_flag)){ if (gahbcfg.b.glblintrmsk) return ((gintsts.d32 & gintmsk.d32) & gintmsk_common.d32); else return 0; - } else { - /* Our IRQ kicker is no longer the USB hardware, it's the MPHI interface. - * Can't trust the global interrupt mask bit in this case. - */ - return ((gintsts.d32 & gintmsk.d32) & gintmsk_common.d32); - } } @@ -1605,7 +1586,7 @@ int32_t dwc_otg_handle_common_intr(void *dev) { int retval = 0; gintsts_data_t gintsts; - gintmsk_data_t gintmsk_reenable = { .d32 = 0 }; + gintsts_data_t gintsts_tmp; gpwrdn_data_t gpwrdn = {.d32 = 0 }; dwc_otg_device_t *otg_dev = dev; dwc_otg_core_if_t *core_if = otg_dev->core_if; @@ -1633,10 +1614,7 @@ int32_t dwc_otg_handle_common_intr(void *dev) } if (core_if->hibernation_suspend <= 0) { - /* read_common will have to poke the FIQ's saved mask. We must then clear this mask at the end - * of this handler - god only knows why it's done like this - */ - gintsts.d32 = dwc_otg_read_common_intr(core_if, &gintmsk_reenable, otg_dev->hcd); + gintsts.d32 = dwc_otg_read_common_intr(core_if); if (gintsts.b.modemismatch) { retval |= dwc_otg_handle_mode_mismatch_intr(core_if); @@ -1648,7 +1626,15 @@ int32_t dwc_otg_handle_common_intr(void *dev) retval |= dwc_otg_handle_conn_id_status_change_intr(core_if); } if (gintsts.b.disconnect) { + if (gintsts.b.portintr && dwc_otg_is_host_mode(core_if)) retval |= dwc_otg_handle_disconnect_intr(core_if); + else + { + gintsts_tmp.d32 = 0; + gintsts_tmp.b.disconnect = 1; + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts_tmp.d32); + retval |= 1; + } } if (gintsts.b.sessreqintr) { retval |= dwc_otg_handle_session_req_intr(core_if); @@ -1732,17 +1718,8 @@ 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; - gintmsk_reenable.b.portintr = 1; } - /* Did we actually handle anything? if so, unmask the interrupt */ -// fiq_print(FIQDBG_INT, otg_dev->hcd->fiq_state, "CILOUT %1d", retval); -// fiq_print(FIQDBG_INT, otg_dev->hcd->fiq_state, "%08x", gintsts.d32); -// fiq_print(FIQDBG_INT, otg_dev->hcd->fiq_state, "%08x", gintmsk_reenable.d32); - if (retval && fiq_enable &&core_if->use_fiq_flag) { - DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, gintmsk_reenable.d32); - } - } else { DWC_DEBUGPL(DBG_ANY, "gpwrdn=%08x\n", gpwrdn.d32); diff --git a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_core_if.h b/drivers/amlogic/usb/dwc_otg/310/dwc_otg_core_if.h old mode 100755 new mode 100644 diff --git a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_driver.c b/drivers/amlogic/usb/dwc_otg/310/dwc_otg_driver.c index 4c643b5e1dff..00a1576216c0 100644 --- a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_driver.c +++ b/drivers/amlogic/usb/dwc_otg/310/dwc_otg_driver.c @@ -57,7 +57,6 @@ #include "dwc_otg_cil.h" #include "dwc_otg_pcd_if.h" #include "dwc_otg_hcd_if.h" -#include "dwc_otg_fiq_fsm.h" #include #include @@ -73,7 +72,6 @@ #define DWC_DRIVER_VERSION "3.10a 12-MAY-2014" #define DWC_DRIVER_DESC "HS OTG USB Controller driver" -bool microframe_schedule=true; static const char dwc_driver_name[] = "dwc_otg"; @@ -271,17 +269,6 @@ static const char *dma_config_name[] = { "BURST_INCR16" "DISABLE", }; - - -//Global variable to switch the fiq fix on or off -bool fiq_enable = 1; -// Global variable to enable the split transaction fix -bool fiq_fsm_enable = true; -//Bulk split-transaction NAK holdoff in microframes -uint16_t nak_holdoff = 8; - -unsigned short fiq_fsm_mask = 0x07; - /** * This function shows the Driver Version. */ @@ -905,7 +892,6 @@ static int dwc_otg_driver_probe( int charger_detect = 0; int host_only_core = 0; int pmu_apply_power = 0; - int use_fiq_flag = 0; unsigned int phy_reg_addr = 0; unsigned int ctrl_reg_addr = 0; const char *s_clock_name = NULL; @@ -914,8 +900,6 @@ static int dwc_otg_driver_probe( struct clk * clock; dwc_otg_device_t *dwc_otg_device; struct dwc_otg_driver_module_params *pcore_para; - int irqno; - unsigned long flags = IRQF_SHARED | IRQF_DISABLED; dev_dbg(&_dev->dev, "dwc_otg_driver_probe(%p)\n", _dev); @@ -949,15 +933,6 @@ static int dwc_otg_driver_probe( struct device_node *of_node = _dev->dev.of_node; match = of_lm_match_node(dwc_otg_dt_match, of_node); if(match){ - gpio_name = of_get_property(of_node, "gpio-pwr", NULL); - if (gpio_name) { - int nr = amlogic_gpio_name_map_num(gpio_name); - amlogic_gpio_request_one(nr, - GPIOF_OUT_INIT_LOW, - "usb_pwr_en"); - amlogic_set_value(nr, 1, "usb_pwr_en"); - } - s_clock_name = of_get_property(of_node, "clock-src", NULL); prop = of_get_property(of_node, "port-id", NULL); if(prop) @@ -1017,11 +992,7 @@ static int dwc_otg_driver_probe( prop = of_get_property(of_node, "pmu-apply-power", NULL); if(prop) pmu_apply_power = of_read_ulong(prop,1); - - prop = of_get_property(of_node, "fiq_use", NULL); - if(prop) - use_fiq_flag = of_read_ulong(prop,1); - + ctrl_reg_addr = (unsigned long)usb_platform_data.ctrl_regaddr[port_index]; phy_reg_addr = (unsigned long)usb_platform_data.phy_regaddr[port_index]; _dev->irq = usb_platform_data.irq_no[port_index]; @@ -1229,20 +1200,14 @@ static int dwc_otg_driver_probe( */ dwc_otg_disable_global_interrupts(dwc_otg_device->core_if); - if(fiq_enable && use_fiq_flag) { - irqno= MESON_USB_FIQ_BRIDGE; - } else { - irqno = _dev->irq; - flags |= IRQ_TYPE_LEVEL_HIGH; - } /* * Install the interrupt handler for the common interrupts before * enabling common interrupts in core_init below. */ DWC_DEBUGPL(DBG_CIL, "registering (common) handler for irq%d\n", - irqno); - retval = request_irq(irqno, dwc_otg_common_irq, - flags, "dwc_otg", + _dev->irq); + retval = request_irq(_dev->irq, dwc_otg_common_irq, + IRQF_SHARED | IRQF_DISABLED | IRQ_LEVEL, "dwc_otg", dwc_otg_device); if (retval) { DWC_ERROR("request of irq%d failed\n", _dev->irq); @@ -1252,6 +1217,11 @@ static int dwc_otg_driver_probe( dwc_otg_device->common_irq_installed = 1; } + if (irq_set_affinity(_dev->irq, cpumask_of(3))) { + pr_warning("unable to set irq affinity (irq=%d, cpu=%u)\n", + _dev->irq, 3); + } + #ifdef LM_INTERFACE // set_irq_type(_dev->irq, IRQT_LOW); #endif @@ -1286,7 +1256,6 @@ static int dwc_otg_driver_probe( if(host_only_core&&pmu_apply_power) dwc_otg_device->core_if->swicth_int_reg = 1; - dwc_otg_device->core_if->use_fiq_flag = use_fiq_flag; if (port_type == USB_PORT_TYPE_HOST) { /* * Initialize the HCD @@ -1437,11 +1406,6 @@ static int __init dwc_otg_driver_init(void) { int retval = 0; int error; - - if(fiq_fsm_enable && !fiq_enable) { - printk(KERN_WARNING "dwc_otg: fiq_fsm_enable was set without fiq_enable! Correcting.\n"); - fiq_enable = 1; - } printk(KERN_INFO "%s: version %s\n", dwc_driver_name, DWC_DRIVER_VERSION); #ifdef LM_INTERFACE @@ -1453,10 +1417,6 @@ 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_enable ? "enabled":"disabled"); - printk(KERN_DEBUG "dwc_otg: NAK holdoff %s\n", nak_holdoff ? "enabled":"disabled"); - printk(KERN_DEBUG "dwc_otg: FIQ split-transaction FSM %s\n", fiq_fsm_enable ? "enabled":"disabled"); - #ifdef LM_INTERFACE error = driver_create_file(&dwc_otg_driver.drv, &driver_attr_version); error = driver_create_file(&dwc_otg_driver.drv, &driver_attr_debuglevel); @@ -1740,22 +1700,6 @@ module_param_named(adp_enable, dwc_otg_module_params.adp_enable, int, 0444); MODULE_PARM_DESC(adp_enable, "ADP Enable 0=ADP Disabled 1=ADP Enabled"); module_param_named(otg_ver, dwc_otg_module_params.otg_ver, int, 0444); 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_enable, bool, 0444); -MODULE_PARM_DESC(fiq_enable, "Enable the FIQ"); -module_param(nak_holdoff, ushort, 0644); -MODULE_PARM_DESC(nak_holdoff, "Throttle duration for bulk split-transaction endpoints on a NAK. Default 8"); -module_param(fiq_fsm_enable, bool, 0444); -MODULE_PARM_DESC(fiq_fsm_enable, "Enable the FIQ to perform split transactions as defined by fiq_fsm_mask"); -module_param(fiq_fsm_mask, ushort, 0444); -MODULE_PARM_DESC(fiq_fsm_mask, "Bitmask of transactions to perform in the FIQ.\n" - "Bit 0 : Non-periodic split transactions\n" - "Bit 1 : Periodic split transactions\n" - "Bit 2 : High-speed multi-transfer isochronous\n" - "All other bits should be set 0."); - /** @page "Module Parameters" * diff --git a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_driver.h b/drivers/amlogic/usb/dwc_otg/310/dwc_otg_driver.h old mode 100755 new mode 100644 index b984ba7f0c93..786b3058153c --- a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_driver.h +++ b/drivers/amlogic/usb/dwc_otg/310/dwc_otg_driver.h @@ -46,7 +46,6 @@ struct dwc_otg_pcd; struct dwc_otg_hcd; -#define MESON_USB_FIQ_BRIDGE INT_TIMER_D /** * This structure is a wrapper that encapsulates the driver components used to * manage a single DWC_otg controller. diff --git a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_fiq_fsm.c b/drivers/amlogic/usb/dwc_otg/310/dwc_otg_fiq_fsm.c deleted file mode 100644 index dcde0357689f..000000000000 --- a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_fiq_fsm.c +++ /dev/null @@ -1,1348 +0,0 @@ -/* - * dwc_otg_fiq_fsm.c - The finite state machine FIQ - * - * Copyright (c) 2013 Raspberry Pi Foundation - * - * Author: Jonathan Bell - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Raspberry Pi nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * This FIQ implements functionality that performs split transactions on - * the dwc_otg hardware without any outside intervention. A split transaction - * is "queued" by nominating a specific host channel to perform the entirety - * of a split transaction. This FIQ will then perform the microframe-precise - * scheduling required in each phase of the transaction until completion. - * - * The FIQ functionality is glued into the Synopsys driver via the entry point - * in the FSM enqueue function, and at the exit point in handling a HC interrupt - * for a FSM-enabled channel. - * - * NB: Large parts of this implementation have architecture-specific code. - * For porting this functionality to other ARM machines, the minimum is required: - * - An interrupt controller allowing the top-level dwc USB interrupt to be routed - * to the FIQ - * - A method of forcing a software generated interrupt from FIQ mode that then - * triggers an IRQ entry (with the dwc USB handler called by this IRQ number) - * - Guaranteed interrupt routing such that both the FIQ and SGI occur on the same - * processor core - there is no locking between the FIQ and IRQ (aside from - * local_fiq_disable) - * - */ - -#include "dwc_otg_fiq_fsm.h" -#include "dwc_otg_driver.h" -#include "mach/register.h" -#include -#include -#include - -char buffer[1000*16]; -int wptr; -void notrace _fiq_print(enum fiq_debug_level dbg_lvl, volatile struct fiq_state *state, char *fmt, ...) -{ - enum fiq_debug_level dbg_lvl_req = FIQDBG_ERR; - va_list args; - char text[17]; - hfnum_data_t hfnum = { .d32 = FIQ_READ(state->dwc_regs_base + 0x408) }; - - if((dbg_lvl & dbg_lvl_req) || dbg_lvl == FIQDBG_ERR) - { - snprintf(text, 9, " %4d:%1u ", hfnum.b.frnum/8, hfnum.b.frnum & 7); - va_start(args, fmt); - vsnprintf(text+8, 9, fmt, args); - va_end(args); - - memcpy(buffer + wptr, text, 16); - wptr = (wptr + 16) % sizeof(buffer); - } -} - -/** - * fiq_fsm_restart_channel() - Poke channel enable bit for a split transaction - * @channel: channel to re-enable - */ -static void fiq_fsm_restart_channel(struct fiq_state *st, int n, int force) -{ - hcchar_data_t hcchar = { .d32 = FIQ_READ(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCCHAR) }; - - hcchar.b.chen = 0; - if (st->channel[n].hcchar_copy.b.eptype & 0x1) { - hfnum_data_t hfnum = { .d32 = FIQ_READ(st->dwc_regs_base + HFNUM) }; - /* Hardware bug workaround: update the ssplit index */ - if (st->channel[n].hcsplt_copy.b.spltena) - st->channel[n].expected_uframe = (hfnum.b.frnum + 1) & 0x3FFF; - - hcchar.b.oddfrm = (hfnum.b.frnum & 0x1) ? 0 : 1; - } - - FIQ_WRITE(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCCHAR, hcchar.d32); - hcchar.d32 = FIQ_READ(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCCHAR); - hcchar.b.chen = 1; - - FIQ_WRITE(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCCHAR, hcchar.d32); - fiq_print(FIQDBG_INT, st, "HCGO %01d %01d", n, force); -} - -/** - * fiq_fsm_setup_csplit() - Prepare a host channel for a CSplit transaction stage - * @st: Pointer to the channel's state - * @n : channel number - * - * Change host channel registers to perform a complete-split transaction. Being mindful of the - * endpoint direction, set control regs up correctly. - */ -static void notrace fiq_fsm_setup_csplit(struct fiq_state *st, int n) -{ - hcsplt_data_t hcsplt = { .d32 = FIQ_READ(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCSPLT) }; - hctsiz_data_t hctsiz = { .d32 = FIQ_READ(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCTSIZ) }; - - hcsplt.b.compsplt = 1; - if (st->channel[n].hcchar_copy.b.epdir == 1) { - // If IN, the CSPLIT result contains the data or a hub handshake. hctsiz = maxpacket. - hctsiz.b.xfersize = st->channel[n].hctsiz_copy.b.xfersize; - } else { - // If OUT, the CSPLIT result contains handshake only. - hctsiz.b.xfersize = 0; - } - FIQ_WRITE(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCSPLT, hcsplt.d32); - FIQ_WRITE(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCTSIZ, hctsiz.d32); - //mb(); -} - -static inline int notrace fiq_get_xfer_len(struct fiq_state *st, int n) -{ - /* The xfersize register is a bit wonky. For IN transfers, it decrements by the packet size. */ - hctsiz_data_t hctsiz = { .d32 = FIQ_READ(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCTSIZ) }; - - if (st->channel[n].hcchar_copy.b.epdir == 0) { - return st->channel[n].hctsiz_copy.b.xfersize; - } else { - return st->channel[n].hctsiz_copy.b.xfersize - hctsiz.b.xfersize; - } - -} - - -/** - * fiq_increment_dma_buf() - update DMA address for bounce buffers after a CSPLIT - * - * Of use only for IN periodic transfers. - */ -static int notrace fiq_increment_dma_buf(struct fiq_state *st, int num_channels, int n) -{ - hcdma_data_t hcdma; - int i = st->channel[n].dma_info.index; - int len; - struct fiq_dma_blob *blob = (struct fiq_dma_blob *) st->dma_base; - - len = fiq_get_xfer_len(st, n); - fiq_print(FIQDBG_INT, st, "LEN: %03d", len); - st->channel[n].dma_info.slot_len[i] = len; - i++; - if (i > 6) - BUG(); - - hcdma.d32 = (dma_addr_t) &blob->channel[n].index[i].buf[0]; - FIQ_WRITE(st->dwc_regs_base + HC_DMA + (HC_OFFSET * n), hcdma.d32); - st->channel[n].dma_info.index = i; - return 0; -} - -/** - * fiq_reload_hctsiz() - for IN transactions, reset HCTSIZ - */ -static void notrace fiq_fsm_reload_hctsiz(struct fiq_state *st, int n) -{ - hctsiz_data_t hctsiz = { .d32 = FIQ_READ(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCTSIZ) }; - hctsiz.b.xfersize = st->channel[n].hctsiz_copy.b.xfersize; - hctsiz.b.pktcnt = 1; - FIQ_WRITE(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCTSIZ, hctsiz.d32); -} - -/** - * fiq_iso_out_advance() - update DMA address and split position bits - * for isochronous OUT transactions. - * - * Returns 1 if this is the last packet queued, 0 otherwise. Split-ALL and - * Split-BEGIN states are not handled - this is done when the transaction was queued. - * - * This function must only be called from the FIQ_ISO_OUT_ACTIVE state. - */ -static int notrace fiq_iso_out_advance(struct fiq_state *st, int num_channels, int n) -{ - hcsplt_data_t hcsplt; - hctsiz_data_t hctsiz; - hcdma_data_t hcdma; - struct fiq_dma_blob *blob = (struct fiq_dma_blob *) st->dma_base; - int last = 0; - int i = st->channel[n].dma_info.index; - - fiq_print(FIQDBG_INT, st, "ADV %01d %01d ", n, i); - i++; - if (i == 4) - last = 1; - if (st->channel[n].dma_info.slot_len[i+1] == 255) - last = 1; - - /* New DMA address - address of bounce buffer referred to in index */ - hcdma.d32 = (uint32_t) &blob->channel[n].index[i].buf[0]; - //hcdma.d32 = FIQ_READ(st->dwc_regs_base + HC_DMA + (HC_OFFSET * n)); - //hcdma.d32 += st->channel[n].dma_info.slot_len[i]; - fiq_print(FIQDBG_INT, st, "LAST: %01d ", last); - fiq_print(FIQDBG_INT, st, "LEN: %03d", st->channel[n].dma_info.slot_len[i]); - hcsplt.d32 = FIQ_READ(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCSPLT); - hctsiz.d32 = FIQ_READ(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCTSIZ); - hcsplt.b.xactpos = (last) ? ISOC_XACTPOS_END : ISOC_XACTPOS_MID; - /* Set up new packet length */ - hctsiz.b.pktcnt = 1; - hctsiz.b.xfersize = st->channel[n].dma_info.slot_len[i]; - fiq_print(FIQDBG_INT, st, "%08x", hctsiz.d32); - - st->channel[n].dma_info.index++; - FIQ_WRITE(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCSPLT, hcsplt.d32); - FIQ_WRITE(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCTSIZ, hctsiz.d32); - FIQ_WRITE(st->dwc_regs_base + HC_DMA + (HC_OFFSET * n), hcdma.d32); - return last; -} - -/** - * fiq_fsm_tt_next_isoc() - queue next pending isochronous out start-split on a TT - * - * Despite the limitations of the DWC core, we can force a microframe pipeline of - * isochronous OUT start-split transactions while waiting for a corresponding other-type - * of endpoint to finish its CSPLITs. TTs have big periodic buffers therefore it - * is very unlikely that filling the start-split FIFO will cause data loss. - * This allows much better interleaving of transactions in an order-independent way- - * there is no requirement to prioritise isochronous, just a state-space search has - * to be performed on each periodic start-split complete interrupt. - */ -static int notrace fiq_fsm_tt_next_isoc(struct fiq_state *st, int num_channels, int n) -{ - int hub_addr = st->channel[n].hub_addr; - int port_addr = st->channel[n].port_addr; - int i, poked = 0; - for (i = 0; i < num_channels; i++) { - if (i == n || st->channel[i].fsm == FIQ_PASSTHROUGH) - continue; - if (st->channel[i].hub_addr == hub_addr && - st->channel[i].port_addr == port_addr) { - switch (st->channel[i].fsm) { - case FIQ_PER_ISO_OUT_PENDING: - if (st->channel[i].nrpackets == 1) { - st->channel[i].fsm = FIQ_PER_ISO_OUT_LAST; - } else { - st->channel[i].fsm = FIQ_PER_ISO_OUT_ACTIVE; - } - fiq_fsm_restart_channel(st, i, 0); - poked = 1; - break; - - default: - break; - } - } - if (poked) - break; - } - return poked; -} - -/** - * fiq_fsm_tt_in_use() - search for host channels using this TT - * @n: Channel to use as reference - * - */ -int notrace noinline fiq_fsm_tt_in_use(struct fiq_state *st, int num_channels, int n) -{ - int hub_addr = st->channel[n].hub_addr; - int port_addr = st->channel[n].port_addr; - int i, in_use = 0; - for (i = 0; i < num_channels; i++) { - if (i == n || st->channel[i].fsm == FIQ_PASSTHROUGH) - continue; - switch (st->channel[i].fsm) { - /* TT is reserved for channels that are in the middle of a periodic - * split transaction. - */ - case FIQ_PER_SSPLIT_STARTED: - case FIQ_PER_CSPLIT_WAIT: - case FIQ_PER_CSPLIT_NYET1: - //case FIQ_PER_CSPLIT_POLL: - case FIQ_PER_ISO_OUT_ACTIVE: - case FIQ_PER_ISO_OUT_LAST: - if (st->channel[i].hub_addr == hub_addr && - st->channel[i].port_addr == port_addr) { - in_use = 1; - } - break; - default: - break; - } - if (in_use) - break; - } - return in_use; -} - -/** - * fiq_fsm_more_csplits() - determine whether additional CSPLITs need - * to be issued for this IN transaction. - * - * We cannot tell the inbound PID of a data packet due to hardware limitations. - * we need to make an educated guess as to whether we need to queue another CSPLIT - * or not. A no-brainer is when we have received enough data to fill the endpoint - * size, but for endpoints that give variable-length data then we have to resort - * to heuristics. - * - * We also return whether this is the last CSPLIT to be queued, again based on - * heuristics. This is to allow a 1-uframe overlap of periodic split transactions. - * Note: requires at least 1 CSPLIT to have been performed prior to being called. - */ - -/* - * We need some way of guaranteeing if a returned periodic packet of size X - * has a DATA0 PID. - * The heuristic value of 144 bytes assumes that the received data has maximal - * bit-stuffing and the clock frequency of the transmitting device is at the lowest - * permissible limit. If the transfer length results in a final packet size - * 144 < p <= 188, then an erroneous CSPLIT will be issued. - * Also used to ensure that an endpoint will nominally only return a single - * complete-split worth of data. - */ -#define DATA0_PID_HEURISTIC 144 - -static int notrace noinline fiq_fsm_more_csplits(struct fiq_state *state, int n, int *probably_last) -{ - - int i; - int total_len = 0; - int more_needed = 1; - struct fiq_channel_state *st = &state->channel[n]; - - for (i = 0; i < st->dma_info.index; i++) { - total_len += st->dma_info.slot_len[i]; - } - - *probably_last = 0; - - if (st->hcchar_copy.b.eptype == 0x3) { - /* - * An interrupt endpoint will take max 2 CSPLITs. if we are receiving data - * then this is definitely the last CSPLIT. - */ - *probably_last = 1; - } else { - /* Isoc IN. This is a bit risky if we are the first transaction: - * we may have been held off slightly. */ - if (i > 1 && st->dma_info.slot_len[st->dma_info.index-1] <= DATA0_PID_HEURISTIC) { - more_needed = 0; - } - /* If in the next uframe we will receive enough data to fill the endpoint, - * then only issue 1 more csplit. - */ - if (st->hctsiz_copy.b.xfersize - total_len <= DATA0_PID_HEURISTIC) - *probably_last = 1; - } - - if (total_len >= st->hctsiz_copy.b.xfersize || - i == 6 || total_len == 0) - /* Note: due to bit stuffing it is possible to have > 6 CSPLITs for - * a single endpoint. Accepting more would completely break our scheduling mechanism though - * - in these extreme cases we will pass through a truncated packet. - */ - more_needed = 0; - - return more_needed; -} - -/** - * fiq_fsm_too_late() - Test transaction for lateness - * - * If a SSPLIT for a large IN transaction is issued too late in a frame, - * the hub will disable the port to the device and respond with ERR handshakes. - * The hub status endpoint will not reflect this change. - * Returns 1 if we will issue a SSPLIT that will result in a device babble. - */ -int notrace fiq_fsm_too_late(struct fiq_state *st, int n) -{ - int uframe; - hfnum_data_t hfnum = { .d32 = FIQ_READ(st->dwc_regs_base + HFNUM) }; - uframe = hfnum.b.frnum & 0x7; - if ((uframe < 6) && (st->channel[n].nrpackets + 1 + uframe > 7)) { - return 1; - } else { - return 0; - } -} - - -/** - * fiq_fsm_start_next_periodic() - A half-arsed attempt at a microframe pipeline - * - * Search pending transactions in the start-split pending state and queue them. - * Don't queue packets in uframe .5 (comes out in .6) (USB2.0 11.18.4). - * Note: we specifically don't do isochronous OUT transactions first because better - * use of the TT's start-split fifo can be achieved by pipelining an IN before an OUT. - */ -static void notrace noinline fiq_fsm_start_next_periodic(struct fiq_state *st, int num_channels) -{ - int n; - hfnum_data_t hfnum = { .d32 = FIQ_READ(st->dwc_regs_base + HFNUM) }; - if ((hfnum.b.frnum & 0x7) == 5) - return; - for (n = 0; n < num_channels; n++) { - if (st->channel[n].fsm == FIQ_PER_SSPLIT_QUEUED) { - /* Check to see if any other transactions are using this TT */ - if(!fiq_fsm_tt_in_use(st, num_channels, n)) { - if (!fiq_fsm_too_late(st, n)) { - st->channel[n].fsm = FIQ_PER_SSPLIT_STARTED; - fiq_print(FIQDBG_INT, st, "NEXTPER "); - fiq_fsm_restart_channel(st, n, 0); - } else { - st->channel[n].fsm = FIQ_PER_SPLIT_TIMEOUT; - } - break; - } - } - } - for (n = 0; n < num_channels; n++) { - if (st->channel[n].fsm == FIQ_PER_ISO_OUT_PENDING) { - if (!fiq_fsm_tt_in_use(st, num_channels, n)) { - fiq_print(FIQDBG_INT, st, "NEXTISO "); - st->channel[n].fsm = FIQ_PER_ISO_OUT_ACTIVE; - fiq_fsm_restart_channel(st, n, 0); - break; - } - } - } -} - -/** - * fiq_fsm_update_hs_isoc() - update isochronous frame and transfer data - * @state: Pointer to fiq_state - * @n: Channel transaction is active on - * @hcint: Copy of host channel interrupt register - * - * Returns 0 if there are no more transactions for this HC to do, 1 - * otherwise. - */ -static int notrace noinline fiq_fsm_update_hs_isoc(struct fiq_state *state, int n, hcint_data_t hcint) -{ - struct fiq_channel_state *st = &state->channel[n]; - int xfer_len = 0, nrpackets = 0; - hcdma_data_t hcdma; - fiq_print(FIQDBG_INT, state, "HSISO %02d", n); - - xfer_len = fiq_get_xfer_len(state, n); - st->hs_isoc_info.iso_desc[st->hs_isoc_info.index].actual_length = xfer_len; - - st->hs_isoc_info.iso_desc[st->hs_isoc_info.index].status = hcint.d32; - - st->hs_isoc_info.index++; - if (st->hs_isoc_info.index == st->hs_isoc_info.nrframes) { - return 0; - } - - /* grab the next DMA address offset from the array */ - hcdma.d32 = st->hcdma_copy.d32 + st->hs_isoc_info.iso_desc[st->hs_isoc_info.index].offset; - FIQ_WRITE(state->dwc_regs_base + HC_DMA + (HC_OFFSET * n), hcdma.d32); - - /* We need to set multi_count. This is a bit tricky - has to be set per-transaction as - * the core needs to be told to send the correct number. Caution: for IN transfers, - * this is always set to the maximum size of the endpoint. */ - xfer_len = st->hs_isoc_info.iso_desc[st->hs_isoc_info.index].length; - /* Integer divide in a FIQ: fun. FIXME: make this not suck */ - nrpackets = (xfer_len + st->hcchar_copy.b.mps - 1) / st->hcchar_copy.b.mps; - if (nrpackets == 0) - nrpackets = 1; - st->hcchar_copy.b.multicnt = nrpackets; - st->hctsiz_copy.b.pktcnt = nrpackets; - - /* Initial PID also needs to be set */ - if (st->hcchar_copy.b.epdir == 0) { - st->hctsiz_copy.b.xfersize = xfer_len; - switch (st->hcchar_copy.b.multicnt) { - case 1: - st->hctsiz_copy.b.pid = DWC_PID_DATA0; - break; - case 2: - case 3: - st->hctsiz_copy.b.pid = DWC_PID_MDATA; - break; - } - - } else { - switch (st->hcchar_copy.b.multicnt) { - st->hctsiz_copy.b.xfersize = nrpackets * st->hcchar_copy.b.mps; - case 1: - st->hctsiz_copy.b.pid = DWC_PID_DATA0; - break; - case 2: - st->hctsiz_copy.b.pid = DWC_PID_DATA1; - break; - case 3: - st->hctsiz_copy.b.pid = DWC_PID_DATA2; - break; - } - } - FIQ_WRITE(state->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCTSIZ, st->hctsiz_copy.d32); - FIQ_WRITE(state->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCCHAR, st->hcchar_copy.d32); - /* Channel is enabled on hcint handler exit */ - fiq_print(FIQDBG_INT, state, "HSISOOUT"); - return 1; -} - -/** - * fiq_fsm_do_sof() - FSM start-of-frame interrupt handler - * @state: Pointer to the state struct passed from banked FIQ mode registers. - * @num_channels: set according to the DWC hardware configuration - * - * The SOF handler in FSM mode has two functions - * 1. Hold off SOF from causing schedule advancement in IRQ context if there's - * nothing to do - * 2. Advance certain FSM states that require either a microframe delay, or a microframe - * of holdoff. - * - * The second part is architecture-specific to mach-bcm2835 - - * a sane interrupt controller would have a mask register for ARM interrupt sources - * to be promoted to the nFIQ line, but it doesn't. Instead a single interrupt - * number (USB) can be enabled. This means that certain parts of the USB specification - * that require "wait a little while, then issue another packet" cannot be fulfilled with - * the timing granularity required to achieve optimal throughout. The workaround is to use - * the SOF "timer" (125uS) to perform this task. - */ -static int notrace noinline fiq_fsm_do_sof(struct fiq_state *state, int num_channels) -{ - hfnum_data_t hfnum = { .d32 = FIQ_READ(state->dwc_regs_base + HFNUM) }; - int n; - int kick_irq = 0; - - if ((hfnum.b.frnum & 0x7) == 1) { - /* We cannot issue csplits for transactions in the last frame past (n+1).1 - * Check to see if there are any transactions that are stale. - * Boot them out. - */ - for (n = 0; n < num_channels; n++) { - switch (state->channel[n].fsm) { - case FIQ_PER_CSPLIT_WAIT: - case FIQ_PER_CSPLIT_NYET1: - case FIQ_PER_CSPLIT_POLL: - case FIQ_PER_CSPLIT_LAST: - /* Check if we are no longer in the same full-speed frame. */ - if (((state->channel[n].expected_uframe & 0x3FFF) & ~0x7) < - (hfnum.b.frnum & ~0x7)) - state->channel[n].fsm = FIQ_PER_SPLIT_TIMEOUT; - break; - default: - break; - } - } - } - - for (n = 0; n < num_channels; n++) { - switch (state->channel[n].fsm) { - - case FIQ_NP_SSPLIT_RETRY: - case FIQ_NP_IN_CSPLIT_RETRY: - case FIQ_NP_OUT_CSPLIT_RETRY: - fiq_fsm_restart_channel(state, n, 0); - break; - - case FIQ_HS_ISOC_SLEEPING: - state->channel[n].fsm = FIQ_HS_ISOC_TURBO; - fiq_fsm_restart_channel(state, n, 0); - break; - - case FIQ_PER_SSPLIT_QUEUED: - if ((hfnum.b.frnum & 0x7) == 5) - break; - if(!fiq_fsm_tt_in_use(state, num_channels, n)) { - if (!fiq_fsm_too_late(state, n)) { - //fiq_print(FIQDBG_INT, st, "SOF GO %01d", n); - fiq_fsm_restart_channel(state, n, 0); - state->channel[n].fsm = FIQ_PER_SSPLIT_STARTED; - } else { - /* Transaction cannot be started without risking a device babble error */ - state->channel[n].fsm = FIQ_PER_SPLIT_TIMEOUT; - state->haintmsk_saved.b2.chint &= ~(1 << n); - FIQ_WRITE(state->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCINTMSK, 0); - kick_irq |= 1; - } - } - break; - - case FIQ_PER_ISO_OUT_PENDING: - /* Ordinarily, this should be poked after the SSPLIT - * complete interrupt for a competing transfer on the same - * TT. Doesn't happen for aborted transactions though. - */ - if ((hfnum.b.frnum & 0x7) >= 5) - break; - if (!fiq_fsm_tt_in_use(state, num_channels, n)) { - /* Hardware bug. SOF can sometimes occur after the channel halt interrupt - * that caused this. - */ - fiq_fsm_restart_channel(state, n, 0); - fiq_print(FIQDBG_INT, state, "SOF ISOC"); - if (state->channel[n].nrpackets == 1) { - state->channel[n].fsm = FIQ_PER_ISO_OUT_LAST; - } else { - state->channel[n].fsm = FIQ_PER_ISO_OUT_ACTIVE; - } - } - break; - - case FIQ_PER_CSPLIT_WAIT: - /* we are guaranteed to be in this state if and only if the SSPLIT interrupt - * occurred when the bus transaction occurred. The SOF interrupt reversal bug - * will utterly bugger this up though. - */ - if (hfnum.b.frnum != state->channel[n].expected_uframe) { - fiq_print(FIQDBG_INT, state, "SOFCS %d ", n); - state->channel[n].fsm = FIQ_PER_CSPLIT_POLL; - fiq_fsm_restart_channel(state, n, 0); - fiq_fsm_start_next_periodic(state, num_channels); - - } - break; - - case FIQ_PER_SPLIT_TIMEOUT: - case FIQ_DEQUEUE_ISSUED: - /* Ugly: we have to force a HCD interrupt. - * Poke the mask for the channel in question. - * We will take a fake SOF because of this, but - * that's OK. - */ - state->haintmsk_saved.b2.chint &= ~(1 << n); - FIQ_WRITE(state->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCINTMSK, 0); - kick_irq |= 1; - break; - - default: - break; - } - } - - if (state->kick_np_queues || - dwc_frame_num_le(state->next_sched_frame, hfnum.b.frnum)) - kick_irq |= 1; - - return !kick_irq; -} - - -/** - * fiq_fsm_do_hcintr() - FSM host channel interrupt handler - * @state: Pointer to the FIQ state struct - * @num_channels: Number of channels as per hardware config - * @n: channel for which HAINT(i) was raised - * - * An important property is that only the CHHLT interrupt is unmasked. Unfortunately, AHBerr is as well. - */ -static int notrace noinline fiq_fsm_do_hcintr(struct fiq_state *state, int num_channels, int n) -{ - hcint_data_t hcint; - hcintmsk_data_t hcintmsk; - hcint_data_t hcint_probe; - hcchar_data_t hcchar; - int handled = 0; - int restart = 0; - int last_csplit = 0; - int start_next_periodic = 0; - struct fiq_channel_state *st = &state->channel[n]; - hfnum_data_t hfnum; - - hcint.d32 = FIQ_READ(state->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCINT); - hcintmsk.d32 = FIQ_READ(state->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCINTMSK); - hcint_probe.d32 = hcint.d32 & hcintmsk.d32; - - if (st->fsm != FIQ_PASSTHROUGH) { - fiq_print(FIQDBG_INT, state, "HC%01d ST%02d", n, st->fsm); - fiq_print(FIQDBG_INT, state, "%08x", hcint.d32); - } - - switch (st->fsm) { - - case FIQ_PASSTHROUGH: - case FIQ_DEQUEUE_ISSUED: - /* doesn't belong to us, kick it upstairs */ - break; - - case FIQ_PASSTHROUGH_ERRORSTATE: - /* We are here to emulate the error recovery mechanism of the dwc HCD. - * Several interrupts are unmasked if a previous transaction failed - it's - * death for the FIQ to attempt to handle them as the channel isn't halted. - * Emulate what the HCD does in this situation: mask and continue. - * The FSM has no other state setup so this has to be handled out-of-band. - */ - fiq_print(FIQDBG_ERR, state, "ERRST %02d", n); - if (hcint_probe.b.nak || hcint_probe.b.ack || hcint_probe.b.datatglerr) { - fiq_print(FIQDBG_ERR, state, "RESET %02d", n); - /* In some random cases we can get a NAK interrupt coincident with a Xacterr - * interrupt, after the device has disappeared. - */ - if (!hcint.b.xacterr) - st->nr_errors = 0; - hcintmsk.b.nak = 0; - hcintmsk.b.ack = 0; - hcintmsk.b.datatglerr = 0; - FIQ_WRITE(state->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCINTMSK, hcintmsk.d32); - return 1; - } - if (hcint_probe.b.chhltd) { - fiq_print(FIQDBG_ERR, state, "CHHLT %02d", n); - fiq_print(FIQDBG_ERR, state, "%08x", hcint.d32); - return 0; - } - break; - - /* Non-periodic state groups */ - case FIQ_NP_SSPLIT_STARTED: - case FIQ_NP_SSPLIT_RETRY: - /* Got a HCINT for a NP SSPLIT. Expected ACK / NAK / fail */ - if (hcint.b.ack) { - /* SSPLIT complete. For OUT, the data has been sent. For IN, the LS transaction - * will start shortly. SOF needs to kick the transaction to prevent a NYET flood. - */ - if(st->hcchar_copy.b.epdir == 1) - st->fsm = FIQ_NP_IN_CSPLIT_RETRY; - else - st->fsm = FIQ_NP_OUT_CSPLIT_RETRY; - st->nr_errors = 0; - handled = 1; - fiq_fsm_setup_csplit(state, n); - } else if (hcint.b.nak) { - // No buffer space in TT. Retry on a uframe boundary. - st->fsm = FIQ_NP_SSPLIT_RETRY; - handled = 1; - } else if (hcint.b.xacterr) { - // The only other one we care about is xacterr. This implies HS bus error - retry. - st->nr_errors++; - st->fsm = FIQ_NP_SSPLIT_RETRY; - if (st->nr_errors >= 3) { - st->fsm = FIQ_NP_SPLIT_HS_ABORTED; - } else { - handled = 1; - restart = 1; - } - } else { - st->fsm = FIQ_NP_SPLIT_LS_ABORTED; - handled = 0; - restart = 0; - } - break; - - case FIQ_NP_IN_CSPLIT_RETRY: - /* Received a CSPLIT done interrupt. - * Expected Data/NAK/STALL/NYET for IN. - */ - if (hcint.b.xfercomp) { - /* For IN, data is present. */ - st->fsm = FIQ_NP_SPLIT_DONE; - } else if (hcint.b.nak) { - /* no endpoint data. Punt it upstairs */ - st->fsm = FIQ_NP_SPLIT_DONE; - } else if (hcint.b.nyet) { - /* CSPLIT NYET - retry on a uframe boundary. */ - handled = 1; - st->nr_errors = 0; - } else if (hcint.b.datatglerr) { - /* data toggle errors do not set the xfercomp bit. */ - st->fsm = FIQ_NP_SPLIT_LS_ABORTED; - } else if (hcint.b.xacterr) { - /* HS error. Retry immediate */ - st->fsm = FIQ_NP_IN_CSPLIT_RETRY; - st->nr_errors++; - if (st->nr_errors >= 3) { - st->fsm = FIQ_NP_SPLIT_HS_ABORTED; - } else { - handled = 1; - restart = 1; - } - } else if (hcint.b.stall || hcint.b.bblerr) { - /* A STALL implies either a LS bus error or a genuine STALL. */ - st->fsm = FIQ_NP_SPLIT_LS_ABORTED; - } else { - /* Hardware bug. It's possible in some cases to - * get a channel halt with nothing else set when - * the response was a NYET. Treat as local 3-strikes retry. - */ - hcint_data_t hcint_test = hcint; - hcint_test.b.chhltd = 0; - if (!hcint_test.d32) { - st->nr_errors++; - if (st->nr_errors >= 3) { - st->fsm = FIQ_NP_SPLIT_HS_ABORTED; - } else { - handled = 1; - } - } else { - /* Bail out if something unexpected happened */ - st->fsm = FIQ_NP_SPLIT_HS_ABORTED; - } - } - break; - - case FIQ_NP_OUT_CSPLIT_RETRY: - /* Received a CSPLIT done interrupt. - * Expected ACK/NAK/STALL/NYET/XFERCOMP for OUT.*/ - if (hcint.b.xfercomp) { - st->fsm = FIQ_NP_SPLIT_DONE; - } else if (hcint.b.nak) { - // The HCD will implement the holdoff on frame boundaries. - st->fsm = FIQ_NP_SPLIT_DONE; - } else if (hcint.b.nyet) { - // Hub still processing. - st->fsm = FIQ_NP_OUT_CSPLIT_RETRY; - handled = 1; - st->nr_errors = 0; - //restart = 1; - } else if (hcint.b.xacterr) { - /* HS error. retry immediate */ - st->fsm = FIQ_NP_OUT_CSPLIT_RETRY; - st->nr_errors++; - if (st->nr_errors >= 3) { - st->fsm = FIQ_NP_SPLIT_HS_ABORTED; - } else { - handled = 1; - restart = 1; - } - } else if (hcint.b.stall) { - /* LS bus error or genuine stall */ - st->fsm = FIQ_NP_SPLIT_LS_ABORTED; - } else { - /* - * Hardware bug. It's possible in some cases to get a - * channel halt with nothing else set when the response was a NYET. - * Treat as local 3-strikes retry. - */ - hcint_data_t hcint_test = hcint; - hcint_test.b.chhltd = 0; - if (!hcint_test.d32) { - st->nr_errors++; - if (st->nr_errors >= 3) { - st->fsm = FIQ_NP_SPLIT_HS_ABORTED; - } else { - handled = 1; - } - } else { - // Something unexpected happened. AHBerror or babble perhaps. Let the IRQ deal with it. - st->fsm = FIQ_NP_SPLIT_HS_ABORTED; - } - } - break; - - /* Periodic split states (except isoc out) */ - case FIQ_PER_SSPLIT_STARTED: - /* Expect an ACK or failure for SSPLIT */ - if (hcint.b.ack) { - /* - * SSPLIT transfer complete interrupt - the generation of this interrupt is fraught with bugs. - * For a packet queued in microframe n-3 to appear in n-2, if the channel is enabled near the EOF1 - * point for microframe n-3, the packet will not appear on the bus until microframe n. - * Additionally, the generation of the actual interrupt is dodgy. For a packet appearing on the bus - * in microframe n, sometimes the interrupt is generated immediately. Sometimes, it appears in n+1 - * coincident with SOF for n+1. - * SOF is also buggy. It can sometimes be raised AFTER the first bus transaction has taken place. - * These appear to be caused by timing/clock crossing bugs within the core itself. - * State machine workaround. - */ - hfnum.d32 = FIQ_READ(state->dwc_regs_base + HFNUM); - hcchar.d32 = FIQ_READ(state->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCCHAR); - fiq_fsm_setup_csplit(state, n); - /* Poke the oddfrm bit. If we are equivalent, we received the interrupt at the correct - * time. If not, then we're in the next SOF. - */ - if ((hfnum.b.frnum & 0x1) == hcchar.b.oddfrm) { - fiq_print(FIQDBG_INT, state, "CSWAIT %01d", n); - st->expected_uframe = hfnum.b.frnum; - st->fsm = FIQ_PER_CSPLIT_WAIT; - } else { - fiq_print(FIQDBG_INT, state, "CSPOL %01d", n); - /* For isochronous IN endpoints, - * we need to hold off if we are expecting a lot of data */ - if (st->hcchar_copy.b.mps < DATA0_PID_HEURISTIC) { - start_next_periodic = 1; - } - /* Danger will robinson: we are in a broken state. If our first interrupt after - * this is a NYET, it will be delayed by 1 uframe and result in an unrecoverable - * lag. Unmask the NYET interrupt. - */ - st->expected_uframe = (hfnum.b.frnum + 1) & 0x3FFF; - st->fsm = FIQ_PER_CSPLIT_BROKEN_NYET1; - restart = 1; - } - handled = 1; - } else if (hcint.b.xacterr) { - /* 3-strikes retry is enabled, we have hit our max nr_errors */ - st->fsm = FIQ_PER_SPLIT_HS_ABORTED; - start_next_periodic = 1; - } else { - st->fsm = FIQ_PER_SPLIT_HS_ABORTED; - start_next_periodic = 1; - } - /* We can now queue the next isochronous OUT transaction, if one is pending. */ - if(fiq_fsm_tt_next_isoc(state, num_channels, n)) { - fiq_print(FIQDBG_INT, state, "NEXTISO "); - } - break; - - case FIQ_PER_CSPLIT_NYET1: - /* First CSPLIT attempt was a NYET. If we get a subsequent NYET, - * we are too late and the TT has dropped its CSPLIT fifo. - */ - hfnum.d32 = FIQ_READ(state->dwc_regs_base + HFNUM); - hcchar.d32 = FIQ_READ(state->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCCHAR); - start_next_periodic = 1; - if (hcint.b.nak) { - st->fsm = FIQ_PER_SPLIT_DONE; - } else if (hcint.b.xfercomp) { - fiq_increment_dma_buf(state, num_channels, n); - st->fsm = FIQ_PER_CSPLIT_POLL; - st->nr_errors = 0; - if (fiq_fsm_more_csplits(state, n, &last_csplit)) { - handled = 1; - restart = 1; - if (!last_csplit) - start_next_periodic = 0; - } else { - st->fsm = FIQ_PER_SPLIT_DONE; - } - } else if (hcint.b.nyet) { - /* Doh. Data lost. */ - st->fsm = FIQ_PER_SPLIT_NYET_ABORTED; - } else if (hcint.b.xacterr || hcint.b.stall || hcint.b.bblerr) { - st->fsm = FIQ_PER_SPLIT_LS_ABORTED; - } else { - st->fsm = FIQ_PER_SPLIT_HS_ABORTED; - } - break; - - case FIQ_PER_CSPLIT_BROKEN_NYET1: - /* - * we got here because our host channel is in the delayed-interrupt - * state and we cannot take a NYET interrupt any later than when it - * occurred. Disable then re-enable the channel if this happens to force - * CSPLITs to occur at the right time. - */ - hfnum.d32 = FIQ_READ(state->dwc_regs_base + HFNUM); - hcchar.d32 = FIQ_READ(state->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCCHAR); - fiq_print(FIQDBG_INT, state, "BROK: %01d ", n); - if (hcint.b.nak) { - st->fsm = FIQ_PER_SPLIT_DONE; - start_next_periodic = 1; - } else if (hcint.b.xfercomp) { - fiq_increment_dma_buf(state, num_channels, n); - if (fiq_fsm_more_csplits(state, n, &last_csplit)) { - st->fsm = FIQ_PER_CSPLIT_POLL; - handled = 1; - restart = 1; - start_next_periodic = 1; - /* Reload HCTSIZ for the next transfer */ - fiq_fsm_reload_hctsiz(state, n); - if (!last_csplit) - start_next_periodic = 0; - } else { - st->fsm = FIQ_PER_SPLIT_DONE; - } - } else if (hcint.b.nyet) { - st->fsm = FIQ_PER_SPLIT_NYET_ABORTED; - start_next_periodic = 1; - } else if (hcint.b.xacterr || hcint.b.stall || hcint.b.bblerr) { - /* Local 3-strikes retry is handled by the core. This is a ERR response.*/ - st->fsm = FIQ_PER_SPLIT_LS_ABORTED; - } else { - st->fsm = FIQ_PER_SPLIT_HS_ABORTED; - } - break; - - case FIQ_PER_CSPLIT_POLL: - hfnum.d32 = FIQ_READ(state->dwc_regs_base + HFNUM); - hcchar.d32 = FIQ_READ(state->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCCHAR); - start_next_periodic = 1; - if (hcint.b.nak) { - st->fsm = FIQ_PER_SPLIT_DONE; - } else if (hcint.b.xfercomp) { - fiq_increment_dma_buf(state, num_channels, n); - if (fiq_fsm_more_csplits(state, n, &last_csplit)) { - handled = 1; - restart = 1; - /* Reload HCTSIZ for the next transfer */ - fiq_fsm_reload_hctsiz(state, n); - if (!last_csplit) - start_next_periodic = 0; - } else { - st->fsm = FIQ_PER_SPLIT_DONE; - } - } else if (hcint.b.nyet) { - /* Are we a NYET after the first data packet? */ - if (st->nrpackets == 0) { - st->fsm = FIQ_PER_CSPLIT_NYET1; - handled = 1; - restart = 1; - } else { - /* We got a NYET when polling CSPLITs. Can happen - * if our heuristic fails, or if someone disables us - * for any significant length of time. - */ - if (st->nr_errors >= 3) { - st->fsm = FIQ_PER_SPLIT_NYET_ABORTED; - } else { - st->fsm = FIQ_PER_SPLIT_DONE; - } - } - } else if (hcint.b.xacterr || hcint.b.stall || hcint.b.bblerr) { - /* For xacterr, Local 3-strikes retry is handled by the core. This is a ERR response.*/ - st->fsm = FIQ_PER_SPLIT_LS_ABORTED; - } else { - st->fsm = FIQ_PER_SPLIT_HS_ABORTED; - } - break; - - case FIQ_HS_ISOC_TURBO: - if (fiq_fsm_update_hs_isoc(state, n, hcint)) { - /* more transactions to come */ - handled = 1; - restart = 1; - fiq_print(FIQDBG_INT, state, "HSISO M "); - } else { - st->fsm = FIQ_HS_ISOC_DONE; - fiq_print(FIQDBG_INT, state, "HSISO F "); - } - break; - - case FIQ_HS_ISOC_ABORTED: - /* This abort is called by the driver rewriting the state mid-transaction - * which allows the dequeue mechanism to work more effectively. - */ - break; - - case FIQ_PER_ISO_OUT_ACTIVE: - if (hcint.b.ack) { - if(fiq_iso_out_advance(state, num_channels, n)) { - /* last OUT transfer */ - st->fsm = FIQ_PER_ISO_OUT_LAST; - /* - * Assuming the periodic FIFO in the dwc core - * actually does its job properly, we can queue - * the next ssplit now and in theory, the wire - * transactions will be in-order. - */ - // No it doesn't. It appears to process requests in host channel order. - //start_next_periodic = 1; - } - handled = 1; - restart = 1; - } else { - /* - * Isochronous transactions carry on regardless. Log the error - * and continue. - */ - //explode += 1; - st->nr_errors++; - if(fiq_iso_out_advance(state, num_channels, n)) { - st->fsm = FIQ_PER_ISO_OUT_LAST; - //start_next_periodic = 1; - } - handled = 1; - restart = 1; - } - break; - - case FIQ_PER_ISO_OUT_LAST: - if (hcint.b.ack) { - /* All done here */ - st->fsm = FIQ_PER_ISO_OUT_DONE; - } else { - st->fsm = FIQ_PER_ISO_OUT_DONE; - st->nr_errors++; - } - start_next_periodic = 1; - break; - - case FIQ_PER_SPLIT_TIMEOUT: - /* SOF kicked us because we overran. */ - start_next_periodic = 1; - break; - - default: - break; - } - - if (handled) { - FIQ_WRITE(state->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCINT, hcint.d32); - } else { - /* Copy the regs into the state so the IRQ knows what to do */ - st->hcint_copy.d32 = hcint.d32; - } - - if (restart) { - /* Restart always implies handled. */ - if (restart == 2) { - /* For complete-split INs, the show must go on. - * Force a channel restart */ - fiq_fsm_restart_channel(state, n, 1); - } else { - fiq_fsm_restart_channel(state, n, 0); - } - } - if (start_next_periodic) { - fiq_fsm_start_next_periodic(state, num_channels); - } - if (st->fsm != FIQ_PASSTHROUGH) - fiq_print(FIQDBG_INT, state, "FSMOUT%02d", st->fsm); - - return handled; -} - -/** - * dwc_otg_fiq_fsm() - Flying State Machine (monster) FIQ - * @state: pointer to state struct passed from the banked FIQ mode registers. - * @num_channels: set according to the DWC hardware configuration - * @dma: pointer to DMA bounce buffers for split transaction slots - * - * The FSM FIQ performs the low-level tasks that normally would be performed by the microcode - * inside an EHCI or similar host controller regarding split transactions. The DWC core - * interrupts each and every time a split transaction packet is received or sent successfully. - * This results in either an interrupt storm when everything is working "properly", or - * the interrupt latency of the system in general breaks time-sensitive periodic split - * transactions. Pushing the low-level, but relatively easy state machine work into the FIQ - * solves these problems. - * - * Return: void - */ -void notrace dwc_otg_fiq_fsm(struct fiq_state *state, int num_channels) -{ - gintsts_data_t gintsts, gintsts_handled; - gintmsk_data_t gintmsk; - //hfnum_data_t hfnum; - haint_data_t haint, haint_handled; - haintmsk_data_t haintmsk; - int kick_irq = 0; - - gintsts_handled.d32 = 0; - haint_handled.d32 = 0; - - gintsts.d32 = FIQ_READ(state->dwc_regs_base + GINTSTS); - gintmsk.d32 = FIQ_READ(state->dwc_regs_base + GINTMSK); - gintsts.d32 &= gintmsk.d32; - - if (gintsts.b.sofintr) { - /* For FSM mode, SOF is required to keep the state machine advance for - * certain stages of the periodic pipeline. It's death to mask this - * interrupt in that case. - */ - - if (!fiq_fsm_do_sof(state, num_channels)) { - /* Kick IRQ once. Queue advancement means that all pending transactions - * will get serviced when the IRQ finally executes. - */ - if (state->gintmsk_saved.b.sofintr == 1) - kick_irq |= 1; - state->gintmsk_saved.b.sofintr = 0; - } - gintsts_handled.b.sofintr = 1; - } - - if (gintsts.b.hcintr) { - int i; - haint.d32 = FIQ_READ(state->dwc_regs_base + HAINT); - haintmsk.d32 = FIQ_READ(state->dwc_regs_base + HAINTMSK); - haint.d32 &= haintmsk.d32; - haint_handled.d32 = 0; - for (i=0; ihaintmsk_saved.b2.chint &= ~(1 << i); - } else { - /* do_hcintr cleaned up after itself, but clear haint */ - haint_handled.b2.chint |= (1 << i); - } - } - } - - if (haint_handled.b2.chint) { - FIQ_WRITE(state->dwc_regs_base + HAINT, haint_handled.d32); - } - - if (haintmsk.d32 != (haintmsk.d32 & state->haintmsk_saved.d32)) { - /* - * This is necessary to avoid multiple retriggers of the MPHI in the case - * where interrupts are held off and HCINTs start to pile up. - * Only wake up the IRQ if a new interrupt came in, was not handled and was - * masked. - */ - haintmsk.d32 &= state->haintmsk_saved.d32; - FIQ_WRITE(state->dwc_regs_base + HAINTMSK, haintmsk.d32); - kick_irq |= 1; - } - /* Top-Level interrupt - always handled because it's level-sensitive */ - gintsts_handled.b.hcintr = 1; - } - - /* Clear the bits in the saved register that were not handled but were triggered. */ - state->gintmsk_saved.d32 &= ~(gintsts.d32 & ~gintsts_handled.d32); - - /* FIQ didn't handle something - mask has changed - write new mask */ - if (gintmsk.d32 != (gintmsk.d32 & state->gintmsk_saved.d32)) { - gintmsk.d32 &= state->gintmsk_saved.d32; - gintmsk.b.sofintr = 1; - FIQ_WRITE(state->dwc_regs_base + GINTMSK, gintmsk.d32); -// fiq_print(FIQDBG_INT, state, "KICKGINT"); -// fiq_print(FIQDBG_INT, state, "%08x", gintmsk.d32); -// fiq_print(FIQDBG_INT, state, "%08x", state->gintmsk_saved.d32); - kick_irq |= 1; - } - - if (gintsts_handled.d32) { - /* Only applies to edge-sensitive bits in GINTSTS */ - FIQ_WRITE(state->dwc_regs_base + GINTSTS, gintsts_handled.d32); - } - - /* We got an interrupt, didn't handle it. */ - //if (kick_irq) { - // state->mphi_int_count++; - // FIQ_WRITE(state->mphi_regs.outdda, (int) state->dummy_send); - // FIQ_WRITE(state->mphi_regs.outddb, (1<<29)); - - //} - state->fiq_done++; - if (kick_irq) - WRITE_CBUS_REG(ISA_TIMERD, 1); - //mb(); -} - -/** - * dwc_otg_fiq_nop() - FIQ "lite" - * @state: pointer to state struct passed from the banked FIQ mode registers. - * - * The "nop" handler does not intervene on any interrupts other than SOF. - * It is limited in scope to deciding at each SOF if the IRQ SOF handler (which deals - * with non-periodic/periodic queues) needs to be kicked. - * - * This is done to hold off the SOF interrupt, which occurs at a rate of 8000 per second. - * - * Return: void - */ -void notrace dwc_otg_fiq_nop(struct fiq_state *state) -{ - gintsts_data_t gintsts, gintsts_handled; - gintmsk_data_t gintmsk; - hfnum_data_t hfnum; - - hfnum.d32 = FIQ_READ(state->dwc_regs_base + HFNUM); - gintsts.d32 = FIQ_READ(state->dwc_regs_base + GINTSTS); - gintmsk.d32 = FIQ_READ(state->dwc_regs_base + GINTMSK); - gintsts.d32 &= gintmsk.d32; - gintsts_handled.d32 = 0; - - if (gintsts.b.sofintr) { - if (!state->kick_np_queues && - dwc_frame_num_gt(state->next_sched_frame, hfnum.b.frnum)) { - /* SOF handled, no work to do, just ACK interrupt */ - gintsts_handled.b.sofintr = 1; - } else { - /* Kick IRQ */ - state->gintmsk_saved.b.sofintr = 0; - } - } - - /* Reset handled interrupts */ - if(gintsts_handled.d32) { - FIQ_WRITE(state->dwc_regs_base + GINTSTS, gintsts_handled.d32); - } - - /* Clear the bits in the saved register that were not handled but were triggered. */ - state->gintmsk_saved.d32 &= ~(gintsts.d32 & ~gintsts_handled.d32); - - /* We got an interrupt, didn't handle it and want to mask it */ - if (~(state->gintmsk_saved.d32)) { - state->mphi_int_count++; - gintmsk.d32 &= state->gintmsk_saved.d32; - FIQ_WRITE(state->dwc_regs_base + GINTMSK, gintmsk.d32); - /* Force a clear before another dummy send */ - FIQ_WRITE(state->mphi_regs.intstat, (1<<29)); - FIQ_WRITE(state->mphi_regs.outdda, (int) state->dummy_send); - FIQ_WRITE(state->mphi_regs.outddb, (1<<29)); - - } - state->fiq_done++; - WRITE_CBUS_REG(ISA_TIMERD, 1); - //mb(); -} - -/**************************************************************** - * work around here - * Sometimes GIC FIQ trigger into IRQ mode -*****************************************************************/ -long fiq_parament[2]; - -void set_fiq_parament(unsigned int fiq,long data) -{ - fiq_parament[fiq-INT_USB_A] = data; -} - -long get_fiq_parament(unsigned int fiq) -{ - return fiq_parament[fiq-INT_USB_A]; -} - -void fiq_isr_fake(unsigned int fiq) -{ - struct fiq_state *state; - int num_channels; - dwc_otg_hcd_t *dwc_otg_hcd; - - dwc_otg_hcd = (dwc_otg_hcd_t *)get_fiq_parament(fiq); - - state = dwc_otg_hcd->fiq_state; - if (fiq_fsm_enable) { - num_channels = dwc_otg_hcd->core_if->core_params->host_channels; - dwc_otg_fiq_fsm(state,num_channels); - } else { - dwc_otg_fiq_nop(state); - } -} - -void handle_fasteoi_irq_fake(unsigned int irq, struct irq_desc *desc) -{ - raw_spin_lock(&desc->lock); - fiq_isr_fake(irq); - desc->irq_data.chip->irq_eoi(&desc->irq_data); - raw_spin_unlock(&desc->lock); - return; -} - -extern void gic_set_fiq_fake(unsigned fiq,irq_flow_handler_t handle); -void set_fiq_init(unsigned int fiq,long data) -{ - // Enable FIQ interrupt from USB peripheral - gic_set_fiq_fake(fiq, handle_fasteoi_irq_fake); - set_fiq_parament(fiq,data); - enable_fiq(fiq); -} diff --git a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_fiq_fsm.h b/drivers/amlogic/usb/dwc_otg/310/dwc_otg_fiq_fsm.h deleted file mode 100644 index f70660761e6b..000000000000 --- a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_fiq_fsm.h +++ /dev/null @@ -1,354 +0,0 @@ -/* - * dwc_otg_fiq_fsm.h - Finite state machine FIQ header definitions - * - * Copyright (c) 2013 Raspberry Pi Foundation - * - * Author: Jonathan Bell - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Raspberry Pi nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * This FIQ implements functionality that performs split transactions on - * the dwc_otg hardware without any outside intervention. A split transaction - * is "queued" by nominating a specific host channel to perform the entirety - * of a split transaction. This FIQ will then perform the microframe-precise - * scheduling required in each phase of the transaction until completion. - * - * The FIQ functionality has been surgically implanted into the Synopsys - * vendor-provided driver. - * - */ - -#ifndef DWC_OTG_FIQ_FSM_H_ -#define DWC_OTG_FIQ_FSM_H_ - -#include "dwc_otg_regs.h" -#include "dwc_otg_cil.h" -#include "dwc_otg_hcd.h" -#include -#include -#include -#include - -#if 0 -#define FLAME_ON(x) \ -do { \ - int gpioreg; \ - \ - gpioreg = readl(__io_address(0x20200000+0x8)); \ - gpioreg &= ~(7 << (x-20)*3); \ - gpioreg |= 0x1 << (x-20)*3; \ - writel(gpioreg, __io_address(0x20200000+0x8)); \ - \ - writel(1< 1, SOF wakes up the isochronous FSM */ - FIQ_HS_ISOC_SLEEPING = 24, - FIQ_HS_ISOC_DONE = 25, - FIQ_HS_ISOC_ABORTED = 26, - FIQ_DEQUEUE_ISSUED = 30, - FIQ_TEST = 32, -}; - -struct fiq_stack { - int magic1; - uint8_t stack[2048]; - int magic2; -}; - - -/** - * struct fiq_dma_info - DMA bounce buffer utilisation information (per-channel) - * @index: Number of slots reported used for IN transactions / number of slots - * transmitted for an OUT transaction - * @slot_len[6]: Number of actual transfer bytes in each slot (255 if unused) - * - * Split transaction transfers can have variable length depending on other bus - * traffic. The OTG core DMA engine requires 4-byte aligned addresses therefore - * each transaction needs a guaranteed aligned address. A maximum of 6 split transfers - * can happen per-frame. - */ -struct fiq_dma_info { - u8 index; - u8 slot_len[6]; -}; - -struct __attribute__((packed)) fiq_split_dma_slot { - u8 buf[188]; -}; - -struct fiq_dma_channel { - struct __attribute__((packed)) fiq_split_dma_slot index[6]; -}; - -struct fiq_dma_blob { - struct __attribute__((packed)) fiq_dma_channel channel[0]; -}; - -/** - * struct fiq_hs_isoc_info - USB2.0 isochronous data - * @iso_frame: Pointer to the array of OTG URB iso_frame_descs. - * @nrframes: Total length of iso_frame_desc array - * @index: Current index (FIQ-maintained) - * - */ -struct fiq_hs_isoc_info { - struct dwc_otg_hcd_iso_packet_desc *iso_desc; - unsigned int nrframes; - unsigned int index; -}; - -/** - * struct fiq_channel_state - FIQ state machine storage - * @fsm: Current state of the channel as understood by the FIQ - * @nr_errors: Number of transaction errors on this split-transaction - * @hub_addr: SSPLIT/CSPLIT destination hub - * @port_addr: SSPLIT/CSPLIT destination port - always 1 if single TT hub - * @nrpackets: For isoc OUT, the number of split-OUT packets to transmit. For - * split-IN, number of CSPLIT data packets that were received. - * @hcchar_copy: - * @hcsplt_copy: - * @hcintmsk_copy: - * @hctsiz_copy: Copies of the host channel registers. - * For use as scratch, or for returning state. - * - * The fiq_channel_state is state storage between interrupts for a host channel. The - * FSM state is stored here. Members of this structure must only be set up by the - * driver prior to enabling the FIQ for this host channel, and not touched until the FIQ - * has updated the state to either a COMPLETE state group or ABORT state group. - */ - -struct fiq_channel_state { - enum fiq_fsm_state fsm; - unsigned int nr_errors; - unsigned int hub_addr; - unsigned int port_addr; - /* Hardware bug workaround: sometimes channel halt interrupts are - * delayed until the next SOF. Keep track of when we expected to get interrupted. */ - unsigned int expected_uframe; - /* in/out for communicating number of dma buffers used, or number of ISOC to do */ - unsigned int nrpackets; - struct fiq_dma_info dma_info; - struct fiq_hs_isoc_info hs_isoc_info; - /* Copies of HC registers - in/out communication from/to IRQ handler - * and for ease of channel setup. A bit of mungeing is performed - for - * example the hctsiz.b.maxp is _always_ the max packet size of the endpoint. - */ - hcchar_data_t hcchar_copy; - hcsplt_data_t hcsplt_copy; - hcint_data_t hcint_copy; - hcintmsk_data_t hcintmsk_copy; - hctsiz_data_t hctsiz_copy; - hcdma_data_t hcdma_copy; -}; - -/** - * struct fiq_state - top-level FIQ state machine storage - * @mphi_regs: virtual address of the MPHI peripheral register file - * @dwc_regs_base: virtual address of the base of the DWC core register file - * @dma_base: physical address for the base of the DMA bounce buffers - * @dummy_send: Scratch area for sending a fake message to the MPHI peripheral - * @gintmsk_saved: Top-level mask of interrupts that the FIQ has not handled. - * Used for determining which interrupts fired to set off the IRQ handler. - * @haintmsk_saved: Mask of interrupts from host channels that the FIQ did not handle internally. - * @np_count: Non-periodic transactions in the active queue - * @np_sent: Count of non-periodic transactions that have completed - * @next_sched_frame: For periodic transactions handled by the driver's SOF-driven queuing mechanism, - * this is the next frame on which a SOF interrupt is required. Used to hold off - * passing SOF through to the driver until necessary. - * @channel[n]: Per-channel FIQ state. Allocated during init depending on the number of host - * channels configured into the core logic. - * - * This is passed as the first argument to the dwc_otg_fiq_fsm top-level FIQ handler from the asm stub. - * It contains top-level state information. - */ -struct fiq_state { - mphi_regs_t mphi_regs; - void *dwc_regs_base; - dma_addr_t dma_base; - struct fiq_dma_blob *fiq_dmab; - void *dummy_send; - gintmsk_data_t gintmsk_saved; - haintmsk_data_t haintmsk_saved; - int mphi_int_count; - unsigned int fiq_done; - unsigned int kick_np_queues; - unsigned int next_sched_frame; -#ifdef FIQ_DEBUG - char * buffer; - unsigned int bufsiz; -#endif - struct fiq_channel_state channel[0]; -}; - -extern int fiq_fsm_too_late(struct fiq_state *st, int n); - -extern int fiq_fsm_tt_in_use(struct fiq_state *st, int num_channels, int n); - -extern void dwc_otg_fiq_fsm(struct fiq_state *state, int num_channels); - -extern void dwc_otg_fiq_nop(struct fiq_state *state); -extern void set_fiq_init(unsigned int fiq,long data); - -#endif /* DWC_OTG_FIQ_FSM_H_ */ diff --git a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_fiq_stub.S b/drivers/amlogic/usb/dwc_otg/310/dwc_otg_fiq_stub.S deleted file mode 100644 index 8cfe3644b5bd..000000000000 --- a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_fiq_stub.S +++ /dev/null @@ -1,81 +0,0 @@ -/* - * dwc_otg_fiq_fsm.S - assembly stub for the FSM FIQ - * - * Copyright (c) 2013 Raspberry Pi Foundation - * - * Author: Jonathan Bell - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Raspberry Pi nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - -#include -#include - - -.text - -.global _dwc_otg_fiq_stub_end; - -/** - * _dwc_otg_fiq_stub() - entry copied to the FIQ vector page to allow - * a C-style function call with arguments from the FIQ banked registers. - * r0 = &hcd->fiq_state - * r1 = &hcd->num_channels - * r2 = &hcd->dma_buffers - * Tramples: r0, r1, r2, r4, fp, ip - */ - -ENTRY(_dwc_otg_fiq_stub) - /* Stash unbanked regs - SP will have been set up for us */ - mov ip, sp; - stmdb sp!, {r0-r12, lr}; -#ifdef FIQ_DEBUG - // Cycle profiling - read cycle counter at start - mrc p15, 0, r5, c15, c12, 1; -#endif - /* r11 = fp, don't trample it */ - mov r4, fp; - /* set EABI frame size */ - sub fp, ip, #512; - - /* for fiq NOP mode - just need state */ - mov r0, r8; - /* r9 = num_channels */ - mov r1, r9; - /* r10 = struct *dma_bufs */ -// mov r2, r10; - - /* r4 = &fiq_c_function */ - blx r4; -#ifdef FIQ_DEBUG - mrc p15, 0, r4, c15, c12, 1; - subs r5, r5, r4; - // r5 is now the cycle count time for executing the FIQ. Store it somewhere? -#endif - ldmia sp!, {r0-r12, lr}; - subs pc, lr, #4; -_dwc_otg_fiq_stub_end: -END(_dwc_otg_fiq_stub) - diff --git a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_hcd.c b/drivers/amlogic/usb/dwc_otg/310/dwc_otg_hcd.c old mode 100755 new mode 100644 index b787cf953050..0820de183fe6 --- a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_hcd.c +++ b/drivers/amlogic/usb/dwc_otg/310/dwc_otg_hcd.c @@ -39,24 +39,8 @@ * header file. */ -#include -#include - #include "dwc_otg_hcd.h" #include "dwc_otg_regs.h" -#include "dwc_otg_fiq_fsm.h" - -extern bool microframe_schedule; -extern uint16_t fiq_fsm_mask, nak_holdoff; - -//#define DEBUG_HOST_CHANNELS -#ifdef DEBUG_HOST_CHANNELS -static int last_sel_trans_num_per_scheduled = 0; -static int last_sel_trans_num_nonper_scheduled = 0; -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 */ - dwc_otg_hcd_t *dwc_otg_hcd_alloc_hcd(void) { @@ -188,18 +172,6 @@ static void kill_urbs_in_qh_list(dwc_otg_hcd_t * hcd, dwc_list_link_t * qh_list) 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); } @@ -305,8 +277,7 @@ 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_enable && dwc_otg_hcd->core_if->use_fiq_flag) - local_fiq_disable(); + /* * Shutdown any transfers in process by clearing the Tx FIFO Empty * interrupt mask and status bits and disabling subsequent host @@ -321,8 +292,6 @@ static int32_t dwc_otg_hcd_disconnect_cb(void *p) DWC_MODIFY_REG32(&dwc_otg_hcd->core_if->core_global_regs->gintsts, intr.d32, 0); - del_timers(dwc_otg_hcd); - /* * Turn off the vbus power only if the core has transitioned to device * mode. If still in host mode, need to keep power on to detect a @@ -337,6 +306,8 @@ static int32_t dwc_otg_hcd_disconnect_cb(void *p) hprt0.d32); dwc_otg_set_vbus_power(dwc_otg_hcd->core_if, 0); //Power off VBus } + /** Delete timers if become device */ + del_timers(dwc_otg_hcd); dwc_otg_disable_host_interrupts(dwc_otg_hcd->core_if); } @@ -420,17 +391,8 @@ static int32_t dwc_otg_hcd_disconnect_cb(void *p) channel->qh = NULL; } } - if(fiq_fsm_enable && dwc_otg_hcd->core_if->use_fiq_flag) { - for(i=0; i < 128; i++) { - dwc_otg_hcd->hub_port[i] = 0; - } } - } - - if(fiq_enable && dwc_otg_hcd->core_if->use_fiq_flag) - local_fiq_enable(); - if (dwc_otg_hcd->fops->disconnect) { dwc_otg_hcd->fops->disconnect(dwc_otg_hcd); } @@ -479,6 +441,7 @@ static int dwc_otg_hcd_rem_wakeup_cb(void *p) if (hcd->core_if->lx_state == DWC_OTG_L2) { hcd->flags.b.port_suspend_change = 1; + dwc_otg_hcd_start_cb(p); } #ifdef CONFIG_USB_DWC_OTG_LPM else { @@ -518,22 +481,6 @@ void dwc_otg_hcd_stop(dwc_otg_hcd_t * hcd) dwc_mdelay(1); } -void host_hibernation_restore(dwc_otg_hcd_t * hcd) -{ - hprt0_data_t hprt0 = {.d32 = 0 }; - - hprt0.d32 = DWC_READ_REG32(hcd->core_if->host_if->hprt0); - hprt0.b.prtpwr = 0; - DWC_WRITE_REG32(hcd->core_if->host_if->hprt0, hprt0.d32); - - dwc_mdelay(1); - - hprt0.d32 = DWC_READ_REG32(hcd->core_if->host_if->hprt0); - hprt0.b.prtpwr = 1; - DWC_WRITE_REG32(hcd->core_if->host_if->hprt0, hprt0.d32); - -} - static void dwc_otg_hcd_power_save(dwc_otg_hcd_t * hcd, int power_on) { usb_dbg_uart_data_t uart = {.d32 = 0 }; @@ -573,7 +520,6 @@ int dwc_otg_hcd_suspend(dwc_otg_hcd_t * hcd) { hcd->core_if->suspend_mode = 1; DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD SUSPEND\n"); - dwc_otg_hcd_power_save(hcd, 0); return 0; @@ -586,6 +532,7 @@ int dwc_otg_hcd_resume(dwc_otg_hcd_t *hcd) DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD RESUME\n"); + hcd->ssplit_lock = 0; if (hcd->core_if->vbus_power_pin != -1) { if(dwc_otg_is_host_mode(hcd->core_if)) @@ -593,12 +540,8 @@ int dwc_otg_hcd_resume(dwc_otg_hcd_t *hcd) } hcd->core_if->suspend_mode = 0; - dwc_otg_hcd_power_save(hcd, 1); - if (hcd->pm_freeze_flag) { - host_hibernation_restore(hcd); - } - + return 0; } @@ -608,11 +551,9 @@ int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * hcd, { dwc_irqflags_t flags; int retval = 0; - uint8_t needs_scheduling = 0; - dwc_otg_transaction_type_e tr_type; + int bulk_not_asap = 0; dwc_otg_qtd_t *qtd; gintmsk_data_t intr_mask = {.d32 = 0 }; - hprt0_data_t hprt0 = { .d32 = 0 }; if (!hcd->flags.b.port_connect_status) { /* No longer connected. */ @@ -625,15 +566,10 @@ int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * hcd, DWC_ERROR("USB Connect status change processing\n"); 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; - } - } + + if((dwc_otg_urb->pipe_info.pipe_type == UE_BULK) + && !(dwc_otg_urb->flags & URB_GIVEBACK_ASAP)) + bulk_not_asap = 1; DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags); @@ -643,11 +579,6 @@ int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * hcd, retval = -DWC_E_NO_MEMORY; goto OUT; } - intr_mask.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->gintmsk); - if(!intr_mask.b.sofintr || (fiq_enable && hcd->core_if->use_fiq_flag)) 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); @@ -657,11 +588,21 @@ int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * hcd, dwc_otg_hcd_qtd_free(qtd); } - if(needs_scheduling) { + 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 (bulk_not_asap) { + /* Do not schedule SG transcations until qtd has URB_GIVEBACK_ASAP set */ + retval = 0; + goto OUT; + } +// DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags); + 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); } OUT: @@ -691,9 +632,13 @@ int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_t * hcd, } #endif if (urb_qtd->in_process && qh->channel) { + // if(qh->do_split && (hcd->ssplit_lock == dwc_otg_hcd_get_dev_addr(&dwc_otg_urb->pipe_info))){ + // hcd->ssplit_lock = 0; + // DWC_DEBUGPL(DBG_HCD,"release ssplit_lock from dev %d\n",dwc_otg_hcd_get_dev_addr(&dwc_otg_urb->pipe_info)); + // } + // printk(KERN_DEBUG "%s,qh->do_split=%d,addr=%d\n",__func__,qh->do_split,dwc_otg_hcd_get_dev_addr(&dwc_otg_urb->pipe_info)); /* The QTD is in process (it has been assigned to a channel). */ if (hcd->flags.b.port_connect_status) { - int n = qh->channel->hc_num; /* * If still connected (i.e. in host mode), halt the * channel so it can be used for other transfers. If @@ -701,27 +646,22 @@ int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_t * hcd, * written to halt the channel since the core is in * device mode. */ - /* In FIQ FSM mode, we need to shut down carefully. - * The FIQ may attempt to restart a disabled channel */ - if (fiq_fsm_enable&&hcd->core_if->use_fiq_flag && (hcd->fiq_state->channel[n].fsm != FIQ_PASSTHROUGH)) { - qh->channel->halt_status = DWC_OTG_HC_XFER_URB_DEQUEUE; - qh->channel->halt_pending = 1; - hcd->fiq_state->channel[n].fsm = FIQ_DEQUEUE_ISSUED; - } else { + if((dwc_otg_urb->qh_state == URB_STATE_SETED) && + (qh->ep_type == UE_ISOCHRONOUS)){ + //printk(KERN_DEBUG "urb(%p) %d,%p,had been done by host controller\n",dwc_otg_urb->priv,qh->ep_type,dwc_otg_urb); + dwc_otg_urb->qh_state = URB_STATE_DQUEUE; + return -1; + } dwc_otg_hc_halt(hcd->core_if, qh->channel, DWC_OTG_HC_XFER_URB_DEQUEUE); } } - } /* * Free the QTD and clean up the associated QH. Leave the QH in the * schedule if it has any remaining QTDs. */ - DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Dequeue - " - "delete %sQueue handler\n", - hcd->core_if->dma_desc_enable?"DMA ":""); if (!hcd->core_if->dma_desc_enable) { uint8_t b = urb_qtd->in_process; dwc_otg_hcd_qtd_remove_and_free(hcd, urb_qtd, qh); @@ -734,6 +674,9 @@ int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_t * hcd, } else { dwc_otg_hcd_qtd_remove_and_free(hcd, urb_qtd, qh); } + + dwc_otg_urb->qh_state = URB_STATE_UNLINK; + return 0; } @@ -803,7 +746,6 @@ static dwc_otg_cil_callbacks_t hcd_cil_callbacks = { #ifdef CONFIG_USB_DWC_OTG_LPM .sleep = dwc_otg_hcd_sleep_cb, #endif - .p = 0, }; /** @@ -827,32 +769,78 @@ static void reset_tasklet_func(void *data) dwc_otg_hcd->flags.b.port_reset_change = 1; } -static void completion_tasklet_func(void *ptr) +/** + * Isoc complete tasklet function + */ +static void isoc_complete_tasklet_func(void * data) { - dwc_otg_hcd_t *hcd = (dwc_otg_hcd_t *) ptr; - struct urb *urb; - urb_tq_entry_t *item; - dwc_irqflags_t flags; + dwc_otg_hcd_t *dwc_otg_hcd = (dwc_otg_hcd_t *) data; +#if 0 + dwc_otg_hcd_urb_t *urb = NULL; + dwc_list_link_t *iso_comp_urb_entry; + dwc_otg_hcd_urb_list_t * urb_list; + int cnt=0; +#endif + int i; - /* 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); + while(1){ +#if 0 + DWC_SPINLOCK(dwc_otg_hcd->isoc_comp_urbs_lock); + iso_comp_urb_entry = DWC_LIST_FIRST(&dwc_otg_hcd->isoc_comp_urbs_list); + if (iso_comp_urb_entry != &dwc_otg_hcd->isoc_comp_urbs_list) { + urb_list = DWC_LIST_ENTRY(iso_comp_urb_entry, dwc_otg_hcd_urb_list_t, urb_list_entry); + DWC_LIST_REMOVE(iso_comp_urb_entry); + DWC_SPINUNLOCK(dwc_otg_hcd->isoc_comp_urbs_lock); + urb = urb_list->urb; + DWC_FREE(urb_list); + } + else + { + DWC_SPINUNLOCK(dwc_otg_hcd->isoc_comp_urbs_lock); + break; + } - usb_hcd_giveback_urb(hcd->priv, urb, urb->status); - - - DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags); + if(urb){ + dwc_otg_hcd->fops->complete_in_tasklet(dwc_otg_hcd, urb->priv, urb, 0); + urb=NULL; + } + cnt++; + if(cnt>16) + break; +#endif + for(i = 0; i < MAX_EPS_CHANNELS; i++){ + if(dwc_otg_hcd->isoc_comp_urbs[i]) + break; + } + if(i >= MAX_EPS_CHANNELS) + break; + + dwc_otg_hcd->fops->complete_in_tasklet(dwc_otg_hcd,dwc_otg_hcd->isoc_comp_urbs[i],0,0); + dwc_otg_hcd->isoc_comp_urbs[i] = NULL; } - DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags); return; } +static void isoc_complete_urb_list_free(dwc_otg_hcd_t * hcd) +{ + dwc_list_link_t *iso_comp_urb_entry; + dwc_otg_hcd_urb_list_t * urb_list; + + DWC_SPINLOCK(hcd->isoc_comp_urbs_lock); + iso_comp_urb_entry = DWC_LIST_FIRST(&hcd->isoc_comp_urbs_list); + while(iso_comp_urb_entry != &hcd->isoc_comp_urbs_list) { + urb_list = DWC_LIST_ENTRY(iso_comp_urb_entry, dwc_otg_hcd_urb_list_t, urb_list_entry); + DWC_LIST_REMOVE(iso_comp_urb_entry); + DWC_FREE(urb_list); + iso_comp_urb_entry = DWC_LIST_FIRST(&hcd->isoc_comp_urbs_list); + } + + DWC_SPINUNLOCK(hcd->isoc_comp_urbs_lock); + + return; +} + + static void qh_list_free(dwc_otg_hcd_t * hcd, dwc_list_link_t * qh_list) { dwc_list_link_t *item; @@ -940,34 +928,6 @@ void dwc_otg_hcd_power_up(void *ptr) cil_hcd_start(core_if); } -void dwc_otg_cleanup_fiq_channel(dwc_otg_hcd_t *hcd, uint32_t num) -{ - struct fiq_channel_state *st = &hcd->fiq_state->channel[num]; - struct fiq_dma_blob *blob = hcd->fiq_dmab; - int i; - - st->fsm = FIQ_PASSTHROUGH; - st->hcchar_copy.d32 = 0; - st->hcsplt_copy.d32 = 0; - st->hcint_copy.d32 = 0; - st->hcintmsk_copy.d32 = 0; - st->hctsiz_copy.d32 = 0; - st->hcdma_copy.d32 = 0; - st->nr_errors = 0; - st->hub_addr = 0; - st->port_addr = 0; - st->expected_uframe = 0; - st->nrpackets = 0; - st->dma_info.index = 0; - for (i = 0; i < 6; i++) - st->dma_info.slot_len[i] = 255; - st->hs_isoc_info.index = 0; - st->hs_isoc_info.iso_desc = NULL; - st->hs_isoc_info.nrframes = 0; - - DWC_MEMSET(&blob->channel[num].index[0], 0x6b, 1128); -} - /** * Frees secondary storage associated with the dwc_otg_hcd structure contained * in the struct usb_hcd field. @@ -988,6 +948,8 @@ static void dwc_otg_hcd_free(dwc_otg_hcd_t * dwc_otg_hcd) qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_assigned); qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_queued); + isoc_complete_urb_list_free(dwc_otg_hcd); + /* Free memory for the host channels. */ for (i = 0; i < MAX_EPS_CHANNELS; i++) { dwc_hc_t *hc = dwc_otg_hcd->hc_ptr_array[i]; @@ -1013,16 +975,14 @@ static void dwc_otg_hcd_free(dwc_otg_hcd_t * dwc_otg_hcd) } else if (dwc_otg_hcd->status_buf != NULL) { DWC_FREE(dwc_otg_hcd->status_buf); } - DWC_SPINLOCK_FREE(dwc_otg_hcd->channel_lock); DWC_SPINLOCK_FREE(dwc_otg_hcd->lock); + DWC_SPINLOCK_FREE(dwc_otg_hcd->isoc_comp_urbs_lock); /* Set core_if's lock pointer to NULL */ dwc_otg_hcd->core_if->lock = NULL; DWC_TIMER_FREE(dwc_otg_hcd->conn_timer); DWC_TASK_FREE(dwc_otg_hcd->reset_tasklet); - DWC_TASK_FREE(dwc_otg_hcd->completion_tasklet); - DWC_FREE(dwc_otg_hcd->fiq_state); - + DWC_TASK_FREE(dwc_otg_hcd->isoc_complete_tasklet); #ifdef DWC_DEV_SRPCAP if (dwc_otg_hcd->core_if->power_down == 2 && dwc_otg_hcd->core_if->pwron_timer) { @@ -1032,8 +992,6 @@ static void dwc_otg_hcd_free(dwc_otg_hcd_t * dwc_otg_hcd) DWC_FREE(dwc_otg_hcd); } -int init_hcd_usecs(dwc_otg_hcd_t *_hcd); - int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd, dwc_otg_core_if_t * core_if) { int retval = 0; @@ -1042,15 +1000,19 @@ int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd, dwc_otg_core_if_t * core_if) dwc_hc_t *channel; hcd->lock = DWC_SPINLOCK_ALLOC(); - hcd->channel_lock = DWC_SPINLOCK_ALLOC(); - DWC_DEBUGPL(DBG_HCDV, "init of HCD %p given core_if %p\n", - hcd, core_if); if (!hcd->lock) { DWC_ERROR("Could not allocate lock for pcd"); DWC_FREE(hcd); retval = -DWC_E_NO_MEMORY; goto out; } + hcd->isoc_comp_urbs_lock= DWC_SPINLOCK_ALLOC(); + if (!hcd->isoc_comp_urbs_lock) { + DWC_ERROR("Could not allocate isoc_comp_urbs_lock for hcd"); + DWC_FREE(hcd); + retval = -DWC_E_NO_MEMORY; + goto out; + } hcd->core_if = core_if; /* Register the HCD CIL Callbacks */ @@ -1066,7 +1028,7 @@ int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd, dwc_otg_core_if_t * core_if) DWC_LIST_INIT(&hcd->periodic_sched_ready); DWC_LIST_INIT(&hcd->periodic_sched_assigned); DWC_LIST_INIT(&hcd->periodic_sched_queued); - DWC_TAILQ_INIT(&hcd->completed_urb_list); + DWC_LIST_INIT(&hcd->isoc_comp_urbs_list); /* * Create a host channel descriptor for each host channel implemented * in the controller. Initialize the channel descriptor array. @@ -1094,63 +1056,15 @@ int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd, dwc_otg_core_if_t * core_if) channel); } - if (fiq_enable && hcd->core_if->use_fiq_flag) { - hcd->fiq_state = DWC_ALLOC(sizeof(struct fiq_state) + (sizeof(struct fiq_channel_state) * num_channels)); - if (!hcd->fiq_state) { - retval = -DWC_E_NO_MEMORY; - DWC_ERROR("%s: cannot allocate fiq_state structure\n", __func__); - dwc_otg_hcd_free(hcd); - goto out; - } - DWC_MEMSET(hcd->fiq_state, 0, (sizeof(struct fiq_state) + (sizeof(struct fiq_channel_state) * num_channels))); - - for (i = 0; i < num_channels; i++) { - hcd->fiq_state->channel[i].fsm = FIQ_PASSTHROUGH; - } - hcd->fiq_state->dummy_send = DWC_ALLOC_ATOMIC(16); - - hcd->fiq_state->gintmsk_saved.d32 = ~0; - hcd->fiq_state->haintmsk_saved.b2.chint = ~0; - - /* This bit is terrible and uses no API, but necessary. The FIQ has no concept of DMA pools - * (and if it did, would be a lot slower). This allocates a chunk of memory (~9kiB for 8 host channels) - * for use as transaction bounce buffers in a 2-D array. Our access into this chunk is done by some - * moderately readable array casts. - */ - hcd->fiq_dmab = DWC_DMA_ALLOC((sizeof(struct fiq_dma_channel) * num_channels), &hcd->fiq_state->dma_base); - DWC_WARN("FIQ DMA bounce buffers: virt = 0x%08x dma = 0x%08x len=%d", - (unsigned int)hcd->fiq_dmab, (unsigned int)hcd->fiq_state->dma_base, - sizeof(struct fiq_dma_channel) * num_channels); - - DWC_MEMSET(hcd->fiq_dmab, 0x6b, 9024); - - /* pointer for debug in fiq_print */ - hcd->fiq_state->fiq_dmab = hcd->fiq_dmab; - if (fiq_fsm_enable) { - int i; - for (i=0; i < hcd->core_if->core_params->host_channels; i++) { - dwc_otg_cleanup_fiq_channel(hcd, i); - } - DWC_PRINTF("FIQ FSM acceleration enabled for :\n%s%s%s%s", - (fiq_fsm_mask & 0x1) ? "Non-periodic Split Transactions\n" : "", - (fiq_fsm_mask & 0x2) ? "Periodic Split Transactions\n" : "", - (fiq_fsm_mask & 0x4) ? "High-Speed Isochronous Endpoints\n" : "", - (fiq_fsm_mask & 0x8) ? "Interrupt/Control Split Transaction hack enabled\n" : ""); - } - } - /* Initialize the Connection timeout timer. */ hcd->conn_timer = DWC_TIMER_ALLOC("Connection timer", dwc_otg_hcd_connect_timeout, hcd); - printk(KERN_DEBUG "dwc_otg: Microframe scheduler %s\n", microframe_schedule ? "enabled":"disabled"); - if (microframe_schedule) - init_hcd_usecs(hcd); /* Initialize reset tasklet. */ hcd->reset_tasklet = DWC_TASK_ALLOC("reset_tasklet", reset_tasklet_func, hcd); + /* Initialize ISOC complete tasklet. */ + hcd->isoc_complete_tasklet = DWC_TASK_ALLOC("isoc_complete_tasklet", isoc_complete_tasklet_func, hcd); - hcd->completion_tasklet = DWC_TASK_ALLOC("completion_tasklet", - completion_tasklet_func, hcd); #ifdef DWC_DEV_SRPCAP if (hcd->core_if->power_down == 2) { /* Initialize Power on timer for Host power up in case hibernation */ @@ -1184,12 +1098,6 @@ int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd, dwc_otg_core_if_t * core_if) hcd->frame_list_dma = 0; hcd->periodic_qh_count = 0; hcd->flags.d32 = 0; - - - DWC_MEMSET(hcd->hub_port, 0, sizeof(hcd->hub_port)); -#ifdef FIQ_DEBUG - DWC_MEMSET(hcd->hub_port_alloc, -1, sizeof(hcd->hub_port_alloc)); -#endif out: return retval; } @@ -1220,12 +1128,9 @@ static void dwc_otg_hcd_reinit(dwc_otg_hcd_t * hcd) hcd->core_if->not_clear_hcd_flag=0; hcd->non_periodic_qh_ptr = &hcd->non_periodic_sched_active; - if (!microframe_schedule) { hcd->non_periodic_channels = 0; hcd->periodic_channels = 0; - } else { - hcd->available_host_channels = hcd->core_if->core_params->host_channels; - } + /* * Put all channels in the free channel list and clean up channel * states. @@ -1259,30 +1164,46 @@ static void dwc_otg_hcd_reinit(dwc_otg_hcd_t * hcd) * @param qh Transactions from the first QTD for this QH are selected and * assigned to a free host channel. */ -static void assign_and_init_hc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) +static int assign_and_init_hc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) { dwc_hc_t *hc; dwc_otg_qtd_t *qtd; dwc_otg_hcd_urb_t *urb; void* ptr = NULL; + DWC_DEBUGPL(DBG_HCDV, "%s(%p,%p)\n", __func__, hcd, qh); + + hc = DWC_CIRCLEQ_FIRST(&hcd->free_hc_list); + qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list); urb = qtd->urb; - DWC_DEBUGPL(DBG_HCDV, "%s(%p,%p) - urb %x, actual_length %d\n", __func__, hcd, qh, (unsigned int)urb, urb->actual_length); - - if (((urb->actual_length < 0) || (urb->actual_length > urb->length)) && !dwc_otg_hcd_is_pipe_in(&urb->pipe_info)) - urb->actual_length = urb->length; - - - hc = DWC_CIRCLEQ_FIRST(&hcd->free_hc_list); - + if(qh->do_split && (qtd->complete_split == 0) && (qh->ep_type == UE_BULK)){ + /* flow control for split bulk/control transfer */ + if(dwc_frame_num_gt(qh->sched_frame, hcd->frame_number)){ + //printk("assign_and_init_hc: sched_frame: %d, %d\n",_qh->sched_frame,_hcd->frame_number); + return -1; + } + else{ + qh->sched_frame = dwc_frame_num_inc( + hcd->frame_number,qh->interval); + //printk("assign_and_init_hc: next sched_frame: %d\n",_qh->sched_frame); + } + } + else if(qh->do_split && (qh->ep_type == UE_INTERRUPT)){ + if((hcd->ssplit_lock == 0) || qtd->complete_split) + hcd->ssplit_lock = dwc_otg_hcd_get_dev_addr(&urb->pipe_info); + else{ + return -2; + } + } /* Remove the host channel from the free list. */ DWC_CIRCLEQ_REMOVE_INIT(&hcd->free_hc_list, hc, hc_list_entry); - qh->channel = hc; + urb->qh_state = URB_STATE_ACTIVE; + qh->channel = hc; qh->dwc_otg_urb = urb; qtd->in_process = 1; @@ -1342,13 +1263,7 @@ static void assign_and_init_hc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) hc->do_split = 1; hc->xact_pos = qtd->isoc_split_pos; - /* We don't need to do complete splits anymore */ -// if(fiq_fsm_enable) - if (0) - 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; @@ -1468,7 +1383,8 @@ static void assign_and_init_hc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) ("%s: Failed to allocate memory to handle " "non-dword aligned buffer case\n", __func__); - return; + hcd->ssplit_lock = 0; + return -1; } } if (!hc->ep_is_in) { @@ -1493,511 +1409,10 @@ static void assign_and_init_hc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) dwc_otg_hc_init(hcd->core_if, hc); hc->qh = qh; -} - -/** - * fiq_fsm_transaction_suitable() - Test a QH for compatibility with the FIQ - * @qh: pointer to the endpoint's queue head - * - * Transaction start/end control flow is grafted onto the existing dwc_otg - * mechanisms, to avoid spaghettifying the functions more than they already are. - * This function's eligibility check is altered by debug parameter. - * - * Returns: 0 for unsuitable, 1 implies the FIQ can be enabled for this transaction. - */ - -int fiq_fsm_transaction_suitable(dwc_otg_qh_t *qh) -{ - if (qh->do_split) { - switch (qh->ep_type) { - case UE_CONTROL: - case UE_BULK: - if (fiq_fsm_mask & (1 << 0)) - return 1; - break; - case UE_INTERRUPT: - case UE_ISOCHRONOUS: - if (fiq_fsm_mask & (1 << 1)) - return 1; - break; - default: - break; - } - } else if (qh->ep_type == UE_ISOCHRONOUS) { - if (fiq_fsm_mask & (1 << 2)) { - /* HS ISOCH support. We test for compatibility: - * - DWORD aligned buffers - * - Must be at least 2 transfers (otherwise pointless to use the FIQ) - * If yes, then the fsm enqueue function will handle the state machine setup. - */ - dwc_otg_qtd_t *qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list); - dwc_otg_hcd_urb_t *urb = qtd->urb; - struct dwc_otg_hcd_iso_packet_desc (*iso_descs)[0] = &urb->iso_descs; - int nr_iso_frames = urb->packet_count; - int i; - uint32_t ptr; - - if (nr_iso_frames < 2) - return 0; - for (i = 0; i < nr_iso_frames; i++) { - ptr = urb->dma + iso_descs[i]->offset; - if (ptr & 0x3) { - printk_ratelimited("%s: Non-Dword aligned isochronous frame offset." - " Cannot queue FIQ-accelerated transfer to device %d endpoint %d\n", - __FUNCTION__, qh->channel->dev_addr, qh->channel->ep_num); - return 0; - } - } - return 1; - } - } return 0; } -/** - * fiq_fsm_setup_periodic_dma() - Set up DMA bounce buffers - * @hcd: Pointer to the dwc_otg_hcd struct - * @qh: Pointer to the endpoint's queue head - * - * Periodic split transactions are transmitted modulo 188 bytes. - * This necessitates slicing data up into buckets for isochronous out - * and fixing up the DMA address for all IN transfers. - * - * Returns 1 if the DMA bounce buffers have been used, 0 if the default - * HC buffer has been used. - */ -int fiq_fsm_setup_periodic_dma(dwc_otg_hcd_t *hcd, struct fiq_channel_state *st, dwc_otg_qh_t *qh) - { - int frame_length, i = 0; - uint8_t *ptr = NULL; - dwc_hc_t *hc = qh->channel; - struct fiq_dma_blob *blob; - struct dwc_otg_hcd_iso_packet_desc *frame_desc; - - for (i = 0; i < 6; i++) { - st->dma_info.slot_len[i] = 255; - } - st->dma_info.index = 0; - i = 0; - if (hc->ep_is_in) { - /* - * Set dma_regs to bounce buffer. FIQ will update the - * state depending on transaction progress. - */ - blob = (struct fiq_dma_blob *) hcd->fiq_state->dma_base; - st->hcdma_copy.d32 = (uint32_t) &blob->channel[hc->hc_num].index[0].buf[0]; - /* Calculate the max number of CSPLITS such that the FIQ can time out - * a transaction if it fails. - */ - frame_length = st->hcchar_copy.b.mps; - do { - i++; - frame_length -= 188; - } while (frame_length >= 0); - st->nrpackets = i; - return 1; - } else { - if (qh->ep_type == UE_ISOCHRONOUS) { - - dwc_otg_qtd_t *qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list); - - frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index]; - frame_length = frame_desc->length; - - /* Virtual address for bounce buffers */ - blob = hcd->fiq_dmab; - - ptr = qtd->urb->buf + frame_desc->offset; - if (frame_length == 0) { - /* - * for isochronous transactions, we must still transmit a packet - * even if the length is zero. - */ - st->dma_info.slot_len[0] = 0; - st->nrpackets = 1; - } else { - do { - if (frame_length <= 188) { - dwc_memcpy(&blob->channel[hc->hc_num].index[i].buf[0], ptr, frame_length); - st->dma_info.slot_len[i] = frame_length; - ptr += frame_length; - } else { - dwc_memcpy(&blob->channel[hc->hc_num].index[i].buf[0], ptr, 188); - st->dma_info.slot_len[i] = 188; - ptr += 188; - } - i++; - frame_length -= 188; - } while (frame_length > 0); - st->nrpackets = i; - } - ptr = qtd->urb->buf + frame_desc->offset; - /* Point the HC at the DMA address of the bounce buffers */ - blob = (struct fiq_dma_blob *) hcd->fiq_state->dma_base; - st->hcdma_copy.d32 = (uint32_t) &blob->channel[hc->hc_num].index[0].buf[0]; - - /* fixup xfersize to the actual packet size */ - st->hctsiz_copy.b.pid = 0; - st->hctsiz_copy.b.xfersize = st->dma_info.slot_len[0]; - return 1; - } else { - /* For interrupt, single OUT packet required, goes in the SSPLIT from hc_buff. */ - return 0; - } - } -} - -/* - * Pushing a periodic request into the queue near the EOF1 point - * in a microframe causes erroneous behaviour (frmovrun) interrupt. - * Usually, the request goes out on the bus causing a transfer but - * the core does not transfer the data to memory. - * This guard interval (in number of 60MHz clocks) is required which - * must cater for CPU latency between reading the value and enabling - * the channel. - */ -#define PERIODIC_FRREM_BACKOFF 1000 - -int fiq_fsm_queue_isoc_transaction(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh) -{ - dwc_hc_t *hc = qh->channel; - dwc_otg_hc_regs_t *hc_regs = hcd->core_if->host_if->hc_regs[hc->hc_num]; - dwc_otg_qtd_t *qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list); - int frame; - struct fiq_channel_state *st = &hcd->fiq_state->channel[hc->hc_num]; - int xfer_len, nrpackets; - hcdma_data_t hcdma; - hfnum_data_t hfnum; - - if (st->fsm != FIQ_PASSTHROUGH) - return 0; - - st->nr_errors = 0; - - st->hcchar_copy.d32 = 0; - st->hcchar_copy.b.mps = hc->max_packet; - st->hcchar_copy.b.epdir = hc->ep_is_in; - st->hcchar_copy.b.devaddr = hc->dev_addr; - st->hcchar_copy.b.epnum = hc->ep_num; - st->hcchar_copy.b.eptype = hc->ep_type; - - st->hcintmsk_copy.b.chhltd = 1; - - frame = dwc_otg_hcd_get_frame_number(hcd); - st->hcchar_copy.b.oddfrm = (frame & 0x1) ? 0 : 1; - - st->hcchar_copy.b.lspddev = 0; - /* Enable the channel later as a final register write. */ - - st->hcsplt_copy.d32 = 0; - - st->hs_isoc_info.iso_desc = (struct dwc_otg_hcd_iso_packet_desc *) &qtd->urb->iso_descs; - st->hs_isoc_info.nrframes = qtd->urb->packet_count; - /* grab the next DMA address offset from the array */ - st->hcdma_copy.d32 = qtd->urb->dma; - hcdma.d32 = st->hcdma_copy.d32 + st->hs_isoc_info.iso_desc[0].offset; - - /* We need to set multi_count. This is a bit tricky - has to be set per-transaction as - * the core needs to be told to send the correct number. Caution: for IN transfers, - * this is always set to the maximum size of the endpoint. */ - xfer_len = st->hs_isoc_info.iso_desc[0].length; - nrpackets = (xfer_len + st->hcchar_copy.b.mps - 1) / st->hcchar_copy.b.mps; - if (nrpackets == 0) - nrpackets = 1; - st->hcchar_copy.b.multicnt = nrpackets; - st->hctsiz_copy.b.pktcnt = nrpackets; - - /* Initial PID also needs to be set */ - if (st->hcchar_copy.b.epdir == 0) { - st->hctsiz_copy.b.xfersize = xfer_len; - switch (st->hcchar_copy.b.multicnt) { - case 1: - st->hctsiz_copy.b.pid = DWC_PID_DATA0; - break; - case 2: - case 3: - st->hctsiz_copy.b.pid = DWC_PID_MDATA; - break; - } - - } else { - st->hctsiz_copy.b.xfersize = nrpackets * st->hcchar_copy.b.mps; - switch (st->hcchar_copy.b.multicnt) { - case 1: - st->hctsiz_copy.b.pid = DWC_PID_DATA0; - break; - case 2: - st->hctsiz_copy.b.pid = DWC_PID_DATA1; - break; - case 3: - st->hctsiz_copy.b.pid = DWC_PID_DATA2; - break; - } - } - - fiq_print(FIQDBG_INT, hcd->fiq_state, "FSMQ %01d ", hc->hc_num); - fiq_print(FIQDBG_INT, hcd->fiq_state, "%08x", st->hcchar_copy.d32); - fiq_print(FIQDBG_INT, hcd->fiq_state, "%08x", st->hctsiz_copy.d32); - fiq_print(FIQDBG_INT, hcd->fiq_state, "%08x", st->hcdma_copy.d32); - hfnum.d32 = DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hfnum); - local_fiq_disable(); - DWC_WRITE_REG32(&hc_regs->hctsiz, st->hctsiz_copy.d32); - DWC_WRITE_REG32(&hc_regs->hcsplt, st->hcsplt_copy.d32); - DWC_WRITE_REG32(&hc_regs->hcdma, st->hcdma_copy.d32); - DWC_WRITE_REG32(&hc_regs->hcchar, st->hcchar_copy.d32); - DWC_WRITE_REG32(&hc_regs->hcintmsk, st->hcintmsk_copy.d32); - if (hfnum.b.frrem < PERIODIC_FRREM_BACKOFF) { - /* Prevent queueing near EOF1. Bad things happen if a periodic - * split transaction is queued very close to EOF. - */ - st->fsm = FIQ_HS_ISOC_SLEEPING; - } else { - st->fsm = FIQ_HS_ISOC_TURBO; - st->hcchar_copy.b.chen = 1; - DWC_WRITE_REG32(&hc_regs->hcchar, st->hcchar_copy.d32); - } - //mb(); - st->hcchar_copy.b.chen = 0; - local_fiq_enable(); - return 0; -} - - -/** - * fiq_fsm_queue_split_transaction() - Set up a host channel and FIQ state - * @hcd: Pointer to the dwc_otg_hcd struct - * @qh: Pointer to the endpoint's queue head - * - * This overrides the dwc_otg driver's normal method of queueing a transaction. - * Called from dwc_otg_hcd_queue_transactions(), this performs specific setup - * for the nominated host channel. - * - * For periodic transfers, it also peeks at the FIQ state to see if an immediate - * start is possible. If not, then the FIQ is left to start the transfer. - */ -int fiq_fsm_queue_split_transaction(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh) -{ - int start_immediate = 1, i; - hfnum_data_t hfnum; - dwc_hc_t *hc = qh->channel; - dwc_otg_hc_regs_t *hc_regs = hcd->core_if->host_if->hc_regs[hc->hc_num]; - /* Program HC registers, setup FIQ_state, examine FIQ if periodic, start transfer (not if uframe 5) */ - int hub_addr, port_addr, frame, uframe; - struct fiq_channel_state *st = &hcd->fiq_state->channel[hc->hc_num]; - - if (st->fsm != FIQ_PASSTHROUGH) - return 0; - st->nr_errors = 0; - - st->hcchar_copy.d32 = 0; - st->hcchar_copy.b.mps = hc->max_packet; - st->hcchar_copy.b.epdir = hc->ep_is_in; - st->hcchar_copy.b.devaddr = hc->dev_addr; - st->hcchar_copy.b.epnum = hc->ep_num; - st->hcchar_copy.b.eptype = hc->ep_type; - if (hc->ep_type & 0x1) { - if (hc->ep_is_in) - st->hcchar_copy.b.multicnt = 3; - else - /* Docs say set this to 1, but driver sets to 0! */ - st->hcchar_copy.b.multicnt = 0; - } else { - st->hcchar_copy.b.multicnt = 1; - st->hcchar_copy.b.oddfrm = 0; - } - st->hcchar_copy.b.lspddev = (hc->speed == DWC_OTG_EP_SPEED_LOW) ? 1 : 0; - /* Enable the channel later as a final register write. */ - - st->hcsplt_copy.d32 = 0; - if(qh->do_split) { - hcd->fops->hub_info(hcd, DWC_CIRCLEQ_FIRST(&qh->qtd_list)->urb->priv, &hub_addr, &port_addr); - st->hcsplt_copy.b.compsplt = 0; - st->hcsplt_copy.b.spltena = 1; - // XACTPOS is for isoc-out only but needs initialising anyway. - st->hcsplt_copy.b.xactpos = ISOC_XACTPOS_ALL; - if((qh->ep_type == DWC_OTG_EP_TYPE_ISOC) && (!qh->ep_is_in)) { - /* For packetsize 0 < L < 188, ISOC_XACTPOS_ALL. - * for longer than this, ISOC_XACTPOS_BEGIN and the FIQ - * will update as necessary. - */ - if (hc->xfer_len > 188) { - st->hcsplt_copy.b.xactpos = ISOC_XACTPOS_BEGIN; - } - } - st->hcsplt_copy.b.hubaddr = (uint8_t) hub_addr; - st->hcsplt_copy.b.prtaddr = (uint8_t) port_addr; - st->hub_addr = hub_addr; - st->port_addr = port_addr; - } - - st->hctsiz_copy.d32 = 0; - st->hctsiz_copy.b.dopng = 0; - st->hctsiz_copy.b.pid = hc->data_pid_start; - - if (hc->ep_is_in || (hc->xfer_len > hc->max_packet)) { - hc->xfer_len = hc->max_packet; - } else if (!hc->ep_is_in && (hc->xfer_len > 188)) { - hc->xfer_len = 188; - } - st->hctsiz_copy.b.xfersize = hc->xfer_len; - - st->hctsiz_copy.b.pktcnt = 1; - - if (hc->ep_type & 0x1) { - /* - * For potentially multi-packet transfers, must use the DMA bounce buffers. For IN transfers, - * the DMA address is the address of the first 188byte slot buffer in the bounce buffer array. - * For multi-packet OUT transfers, we need to copy the data into the bounce buffer array so the FIQ can punt - * the right address out as necessary. hc->xfer_buff and hc->xfer_len have already been set - * in assign_and_init_hc(), but this is for the eventual transaction completion only. The FIQ - * must not touch internal driver state. - */ - if(!fiq_fsm_setup_periodic_dma(hcd, st, qh)) { - if (hc->align_buff) { - st->hcdma_copy.d32 = hc->align_buff; - } else { - st->hcdma_copy.d32 = ((unsigned long) hc->xfer_buff & 0xFFFFFFFF); - } - } - } else { - if (hc->align_buff) { - st->hcdma_copy.d32 = hc->align_buff; - } else { - st->hcdma_copy.d32 = ((unsigned long) hc->xfer_buff & 0xFFFFFFFF); - } - } - /* The FIQ depends upon no other interrupts being enabled except channel halt. - * Fixup channel interrupt mask. */ - st->hcintmsk_copy.d32 = 0; - st->hcintmsk_copy.b.chhltd = 1; - st->hcintmsk_copy.b.ahberr = 1; - - /* Hack courtesy of FreeBSD: apparently forcing Interrupt Split transactions - * as Control puts the transfer into the non-periodic request queue and the - * non-periodic handler in the hub. Makes things lots easier. - */ - if ((fiq_fsm_mask & 0x8) && hc->ep_type == UE_INTERRUPT) { - st->hcchar_copy.b.multicnt = 0; - st->hcchar_copy.b.oddfrm = 0; - st->hcchar_copy.b.eptype = UE_CONTROL; - if (hc->align_buff) { - st->hcdma_copy.d32 = hc->align_buff; - } else { - st->hcdma_copy.d32 = ((unsigned long) hc->xfer_buff & 0xFFFFFFFF); - } - } - DWC_WRITE_REG32(&hc_regs->hcdma, st->hcdma_copy.d32); - DWC_WRITE_REG32(&hc_regs->hctsiz, st->hctsiz_copy.d32); - DWC_WRITE_REG32(&hc_regs->hcsplt, st->hcsplt_copy.d32); - DWC_WRITE_REG32(&hc_regs->hcchar, st->hcchar_copy.d32); - DWC_WRITE_REG32(&hc_regs->hcintmsk, st->hcintmsk_copy.d32); - - local_fiq_disable(); -// mb(); - - if (hc->ep_type & 0x1) { - hfnum.d32 = DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hfnum); - frame = (hfnum.b.frnum & ~0x7) >> 3; - uframe = hfnum.b.frnum & 0x7; - if (hfnum.b.frrem < PERIODIC_FRREM_BACKOFF) { - /* Prevent queueing near EOF1. Bad things happen if a periodic - * split transaction is queued very close to EOF. - */ - start_immediate = 0; - } else if (uframe == 5) { - start_immediate = 0; - } else if (hc->ep_type == UE_ISOCHRONOUS && !hc->ep_is_in) { - start_immediate = 0; - } else if (hc->ep_is_in && fiq_fsm_too_late(hcd->fiq_state, hc->hc_num)) { - start_immediate = 0; - } else { - /* Search through all host channels to determine if a transaction - * is currently in progress */ - for (i = 0; i < hcd->core_if->core_params->host_channels; i++) { - if (i == hc->hc_num || hcd->fiq_state->channel[i].fsm == FIQ_PASSTHROUGH) - continue; - switch (hcd->fiq_state->channel[i].fsm) { - /* TT is reserved for channels that are in the middle of a periodic - * split transaction. - */ - case FIQ_PER_SSPLIT_STARTED: - case FIQ_PER_CSPLIT_WAIT: - case FIQ_PER_CSPLIT_NYET1: - case FIQ_PER_CSPLIT_POLL: - case FIQ_PER_ISO_OUT_ACTIVE: - case FIQ_PER_ISO_OUT_LAST: - if (hcd->fiq_state->channel[i].hub_addr == hub_addr && - hcd->fiq_state->channel[i].port_addr == port_addr) { - start_immediate = 0; - } - break; - default: - break; - } - if (!start_immediate) - break; - } - } - } - if ((fiq_fsm_mask & 0x8) && hc->ep_type == UE_INTERRUPT) - start_immediate = 1; - - fiq_print(FIQDBG_INT, hcd->fiq_state, "FSMQ %01d %01d", hc->hc_num, start_immediate); - fiq_print(FIQDBG_INT, hcd->fiq_state, "%08d", hfnum.b.frrem); - //fiq_print(FIQDBG_INT, hcd->fiq_state, "H:%02dP:%02d", hub_addr, port_addr); - //fiq_print(FIQDBG_INT, hcd->fiq_state, "%08x", st->hctsiz_copy.d32); - //fiq_print(FIQDBG_INT, hcd->fiq_state, "%08x", st->hcdma_copy.d32); - switch (hc->ep_type) { - case UE_CONTROL: - case UE_BULK: - st->fsm = FIQ_NP_SSPLIT_STARTED; - break; - case UE_ISOCHRONOUS: - if (hc->ep_is_in) { - if (start_immediate) { - st->fsm = FIQ_PER_SSPLIT_STARTED; - } else { - st->fsm = FIQ_PER_SSPLIT_QUEUED; - } - } else { - if (start_immediate) { - /* Single-isoc OUT packets don't require FIQ involvement */ - if (st->nrpackets == 1) { - st->fsm = FIQ_PER_ISO_OUT_LAST; - } else { - st->fsm = FIQ_PER_ISO_OUT_ACTIVE; - } - } else { - st->fsm = FIQ_PER_ISO_OUT_PENDING; - } - } - break; - case UE_INTERRUPT: - if (fiq_fsm_mask & 0x8) { - st->fsm = FIQ_NP_SSPLIT_STARTED; - } else if (start_immediate) { - st->fsm = FIQ_PER_SSPLIT_STARTED; - } else { - st->fsm = FIQ_PER_SSPLIT_QUEUED; - } - default: - break; - } - if (start_immediate) { - /* Set the oddfrm bit as close as possible to actual queueing */ - frame = dwc_otg_hcd_get_frame_number(hcd); - st->expected_uframe = (frame + 1) & 0x3FFF; - st->hcchar_copy.b.oddfrm = (frame & 0x1) ? 0 : 1; - st->hcchar_copy.b.chen = 1; - DWC_WRITE_REG32(&hc_regs->hcchar, st->hcchar_copy.d32); - } - //mb(); - local_fiq_enable(); - return 0; -} - - /** * This function selects transactions from the HCD transfer schedule and * assigns them to available host channels. It is called from HCD interrupt @@ -2012,15 +1427,11 @@ dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd) dwc_list_link_t *qh_ptr; dwc_otg_qh_t *qh; int num_channels; - dwc_irqflags_t flags; - dwc_spinlock_t *channel_lock = hcd->channel_lock; dwc_otg_transaction_type_e ret_val = DWC_OTG_TRANSACTION_NONE; -#ifdef DEBUG_HOST_CHANNELS - last_sel_trans_num_per_scheduled = 0; - last_sel_trans_num_nonper_scheduled = 0; - last_sel_trans_num_avail_hc_at_start = hcd->available_host_channels; -#endif /* DEBUG_HOST_CHANNELS */ +#ifdef DEBUG_SOF + DWC_DEBUGPL(DBG_HCD, " Select Transactions\n"); +#endif /* Process entries in the periodic ready list. */ qh_ptr = DWC_LIST_FIRST(&hcd->periodic_sched_ready); @@ -2030,31 +1441,19 @@ dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd) qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry); - 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); - break; - } - hcd->available_host_channels--; - DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags); -#ifdef DEBUG_HOST_CHANNELS - last_sel_trans_num_per_scheduled++; -#endif /* DEBUG_HOST_CHANNELS */ - } - qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry); - assign_and_init_hc(hcd, qh); - /* * Move the QH from the periodic ready schedule to the * periodic assigned schedule. */ qh_ptr = DWC_LIST_NEXT(qh_ptr); - DWC_SPINLOCK_IRQSAVE(channel_lock, &flags); + + if(assign_and_init_hc(hcd, qh)) + continue; + DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_assigned, &qh->qh_list_entry); - DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags); + + ret_val = DWC_OTG_TRANSACTION_PERIODIC; } /* @@ -2065,92 +1464,33 @@ dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd) qh_ptr = hcd->non_periodic_sched_inactive.next; num_channels = hcd->core_if->core_params->host_channels; while (qh_ptr != &hcd->non_periodic_sched_inactive && - (microframe_schedule || hcd->non_periodic_channels < + (hcd->non_periodic_channels < num_channels - hcd->periodic_channels) && !DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) { qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry); - /* - * Check to see if this is a NAK'd retransmit, in which case ignore for retransmission - * we hold off on bulk retransmissions to reduce NAK interrupt overhead for full-speed - * cheeky devices that just hold off using NAKs - */ - if (nak_holdoff && qh->do_split) { - if (qh->nak_frame != 0xffff) { - uint16_t next_frame = dwc_frame_num_inc(qh->nak_frame, (qh->ep_type == UE_BULK) ? nak_holdoff : 8); - uint16_t frame = dwc_otg_hcd_get_frame_number(hcd); - if (dwc_frame_num_le(frame, next_frame)) { - if(dwc_frame_num_le(next_frame, hcd->fiq_state->next_sched_frame)) { - hcd->fiq_state->next_sched_frame = next_frame; - } - qh_ptr = DWC_LIST_NEXT(qh_ptr); - continue; - } else { - qh->nak_frame = 0xFFFF; - } - } - } - - if (microframe_schedule) { - DWC_SPINLOCK_IRQSAVE(channel_lock, &flags); - if (hcd->available_host_channels < 1) { - DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags); - break; - } - hcd->available_host_channels--; - DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags); -#ifdef DEBUG_HOST_CHANNELS - last_sel_trans_num_nonper_scheduled++; -#endif /* DEBUG_HOST_CHANNELS */ - } - - assign_and_init_hc(hcd, qh); /* * Move the QH from the non-periodic inactive schedule to the * non-periodic active schedule. */ qh_ptr = DWC_LIST_NEXT(qh_ptr); - DWC_SPINLOCK_IRQSAVE(channel_lock, &flags); + + if(assign_and_init_hc(hcd, qh)) + continue; + DWC_LIST_MOVE_HEAD(&hcd->non_periodic_sched_active, &qh->qh_list_entry); - DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags); - - if (!microframe_schedule) - hcd->non_periodic_channels++; - } - /* we moved a non-periodic QH to the active schedule. If the inactive queue is empty, - * stop the FIQ from kicking us. We could potentially still have elements here if we - * ran out of host channels. - */ - if (fiq_enable && hcd->core_if->use_fiq_flag) { - if (DWC_LIST_EMPTY(&hcd->non_periodic_sched_inactive)) { - hcd->fiq_state->kick_np_queues = 0; + if (ret_val == DWC_OTG_TRANSACTION_NONE) { + ret_val = DWC_OTG_TRANSACTION_NON_PERIODIC; } else { - /* For each entry remaining in the NP inactive queue, - * if this a NAK'd retransmit then don't set the kick flag. - */ - if(nak_holdoff) { - DWC_LIST_FOREACH(qh_ptr, &hcd->non_periodic_sched_inactive) { - qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry); - if (qh->nak_frame == 0xFFFF) { - hcd->fiq_state->kick_np_queues = 1; - } - } - } + ret_val = DWC_OTG_TRANSACTION_ALL; } + + 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 */ return ret_val; } @@ -2185,12 +1525,6 @@ static int queue_transaction(dwc_otg_hcd_t * hcd, hc->qh->ping_state = 0; } } else if (!hc->xfer_started) { - if (fiq_fsm_enable && hcd->core_if->use_fiq_flag&& hc->error_state) { - hcd->fiq_state->channel[hc->hc_num].nr_errors = - DWC_CIRCLEQ_FIRST(&hc->qh->qtd_list)->error_count; - hcd->fiq_state->channel[hc->hc_num].fsm = - FIQ_PASSTHROUGH_ERRORSTATE; - } dwc_otg_hc_start_transfer(hcd->core_if, hc); hc->qh->ping_state = 0; } @@ -2228,6 +1562,13 @@ static int queue_transaction(dwc_otg_hcd_t * hcd, } } + if(hc->xfer_started){ + if(hc->qh->channel == hc){ + hc->qh->dwc_otg_urb->qh_state = URB_STATE_SETED; + }else + printk("%s hc=%p,qh->channel=%p\n",__func__,hc,hc->qh->channel); + } + return retval; } @@ -2243,7 +1584,7 @@ static void process_periodic_channels(dwc_otg_hcd_t * hcd) hptxsts_data_t tx_status; dwc_list_link_t *qh_ptr; dwc_otg_qh_t *qh; - int status = 0; + int status; int no_queue_space = 0; int no_fifo_space = 0; @@ -2270,24 +1611,8 @@ 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_fsm_enable && hcd->core_if->use_fiq_flag&& qh->do_split && ((dwc_otg_hcd_get_frame_number(hcd) + 1) & 7) > 6) - { - qh_ptr = qh_ptr->next; - hcd->fiq_state->next_sched_frame = dwc_otg_hcd_get_frame_number(hcd) | 7; - continue; - } - - if (fiq_fsm_enable && hcd->core_if->use_fiq_flag && fiq_fsm_transaction_suitable(qh)) { - if (qh->do_split) - fiq_fsm_queue_split_transaction(hcd, qh); - else - fiq_fsm_queue_isoc_transaction(hcd, qh); - } else { - /* - * Set a flag if we're queueing high-bandwidth in slave mode. + * Set a flag if we're queuing high-bandwidth in slave mode. * The flag prevents any halts to get into the request queue in * the middle of multiple high-bandwidth packets getting queued. */ @@ -2301,7 +1626,6 @@ static void process_periodic_channels(dwc_otg_hcd_t * hcd) no_fifo_space = 1; break; } - } /* * In Slave mode, stay on the current transfer until there is @@ -2416,11 +1740,8 @@ 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); - - if(fiq_fsm_enable && hcd->core_if->use_fiq_flag && fiq_fsm_transaction_suitable(qh)) { - fiq_fsm_queue_split_transaction(hcd, qh); - } else { - status = queue_transaction(hcd, qh->channel, + status = + queue_transaction(hcd, qh->channel, tx_status.b.nptxfspcavail); if (status > 0) { @@ -2429,7 +1750,7 @@ static void process_non_periodic_channels(dwc_otg_hcd_t * hcd) no_fifo_space = 1; break; } - } + /* Advance to next QH, skipping start-of-list entry. */ hcd->non_periodic_qh_ptr = hcd->non_periodic_qh_ptr->next; if (hcd->non_periodic_qh_ptr == &hcd->non_periodic_sched_active) { @@ -3951,13 +3272,8 @@ dwc_otg_hcd_urb_t *dwc_otg_hcd_urb_alloc(dwc_otg_hcd_t * hcd, else dwc_otg_urb = DWC_ALLOC(size); - if (dwc_otg_urb) dwc_otg_urb->packet_count = iso_desc_count; - else { - DWC_ERROR("**** DWC OTG HCD URB alloc - " - "%salloc of %db failed\n", - atomic_alloc?"atomic ":"", size); - } + return dwc_otg_urb; } diff --git a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_hcd.h b/drivers/amlogic/usb/dwc_otg/310/dwc_otg_hcd.h old mode 100755 new mode 100644 index 0805da0264f6..c27513e94f21 --- a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_hcd.h +++ b/drivers/amlogic/usb/dwc_otg/310/dwc_otg_hcd.h @@ -40,8 +40,6 @@ #include "dwc_otg_core_if.h" #include "dwc_list.h" #include "dwc_otg_cil.h" -#include "dwc_otg_fiq_fsm.h" - /** * @file @@ -86,10 +84,21 @@ struct dwc_otg_hcd_urb { uint32_t packet_count; uint32_t flags; uint16_t interval; + uint8_t qh_state; +#define URB_STATE_IDLE 1 /* QH is not being used */ +#define URB_STATE_ACTIVE 2 /* QH is on the schedule */ +#define URB_STATE_SETED 3 /* QH had finished setting reg */ +#define URB_STATE_DQUEUE 4 /* QH had been pushed into tasklet, just used for isoc */ +#define URB_STATE_UNLINK 5 /* QH has been removed from the schedule */ struct dwc_otg_hcd_pipe_info pipe_info; struct dwc_otg_hcd_iso_packet_desc iso_descs[0]; }; +typedef struct dwc_otg_hcd_urb_list{ + struct dwc_otg_hcd_urb * urb; + dwc_list_link_t urb_list_entry; +} dwc_otg_hcd_urb_list_t; + static inline uint8_t dwc_otg_hcd_get_ep_num(struct dwc_otg_hcd_pipe_info *pipe) { return pipe->ep_num; @@ -170,10 +179,10 @@ typedef enum dwc_otg_control_phase { /** Transaction types. */ typedef enum dwc_otg_transaction_type { - 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_NONE, + DWC_OTG_TRANSACTION_PERIODIC, + DWC_OTG_TRANSACTION_NON_PERIODIC, + DWC_OTG_TRANSACTION_ALL } dwc_otg_transaction_type_e; struct dwc_otg_qh; @@ -323,11 +332,6 @@ typedef struct dwc_otg_qh { */ uint16_t sched_frame; - /* - ** Frame a NAK was received on this queue head, used to minimise NAK retransmission - */ - uint16_t nak_frame; - /** (micro)frame at which last start split was initialized. */ uint16_t start_split_frame; @@ -370,22 +374,10 @@ typedef struct dwc_otg_qh { struct dwc_otg_hcd_urb *dwc_otg_urb; /** @} */ - - uint16_t speed; - uint16_t frame_usecs[8]; - - uint32_t skip_count; } dwc_otg_qh_t; DWC_CIRCLEQ_HEAD(hc_list, dwc_hc); -typedef struct urb_tq_entry { - struct urb *urb; - DWC_TAILQ_ENTRY(urb_tq_entry) urb_tq_entries; -} urb_tq_entry_t; - -DWC_TAILQ_HEAD(urb_list, urb_tq_entry); - /** * This structure holds the state of the HCD, including the non-periodic and * periodic schedules. @@ -486,19 +478,6 @@ struct dwc_otg_hcd { */ uint16_t periodic_usecs; - /** - * Total bandwidth claimed so far for all periodic transfers - * in a frame. - * This will include a mixture of HS and FS transfers. - * Units are microseconds per (micro)frame. - * We have a budget per frame and have to schedule - * transactions accordingly. - * Watch out for the fact that things are actually scheduled for the - * "next frame". - */ - uint16_t frame_usecs[8]; - - /** * Frame number read from the core at SOF. The value ranges from 0 to * DWC_HFNUM_MAX_FRNUM. @@ -521,17 +500,12 @@ struct dwc_otg_hcd { * transaction and at least one host channel available for * non-periodic transactions. */ - int periodic_channels; /* microframe_schedule==0 */ + int periodic_channels; /** * Number of host channels assigned to non-periodic transfers. */ - int non_periodic_channels; /* microframe_schedule==0 */ - - /** - * Number of host channels assigned to non-periodic transfers. - */ - int available_host_channels; + int non_periodic_channels; /** * Array of pointers to the host channel descriptors. Allows accessing @@ -562,13 +536,13 @@ struct dwc_otg_hcd { /* Tasket to do a reset */ dwc_tasklet_t *reset_tasklet; + dwc_tasklet_t *isoc_complete_tasklet; - dwc_tasklet_t *completion_tasklet; - struct urb_list completed_urb_list; - + dwc_list_link_t isoc_comp_urbs_list; /* */ dwc_spinlock_t *lock; - dwc_spinlock_t *channel_lock; + dwc_spinlock_t * isoc_comp_urbs_lock; + void * isoc_comp_urbs[MAX_EPS_CHANNELS]; /** * Private data that could be used by OS wrapper. */ @@ -579,21 +553,9 @@ struct dwc_otg_hcd { /** Frame List */ uint32_t *frame_list; - /** Hub - Port assignment */ - int hub_port[128]; -#ifdef FIQ_DEBUG - int hub_port_alloc[2048]; -#endif - /** Frame List DMA address */ dma_addr_t frame_list_dma; - struct fiq_stack *fiq_stack; - struct fiq_state *fiq_state; - - /** Virtual address for split transaction DMA bounce buffers */ - struct fiq_dma_blob *fiq_dmab; - #ifdef DEBUG uint32_t frrem_samples; uint64_t frrem_accum; @@ -612,8 +574,8 @@ struct dwc_otg_hcd { uint32_t hfnum_other_samples_b; uint64_t hfnum_other_frrem_accum_b; #endif + uint8_t ssplit_lock; uint8_t auto_pm_suspend_flag; - uint8_t pm_freeze_flag; }; /** @name Transaction Execution Functions */ @@ -623,13 +585,6 @@ 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); - -extern int fiq_fsm_queue_transaction(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh); -extern int fiq_fsm_transaction_suitable(dwc_otg_qh_t *qh); -extern void dwc_otg_cleanup_fiq_channel(dwc_otg_hcd_t *hcd, uint32_t num); - /** @} */ /** @name Interrupt Handler Functions */ @@ -869,5 +824,4 @@ void dwc_otg_hcd_save_data_toggle(dwc_hc_t * hc, #define dwc_sample_frrem(_hcd, _qh, _letter) #endif #endif -#endif -/* DWC_DEVICE_ONLY */ +#endif /* DWC_DEVICE_ONLY */ \ No newline at end of file diff --git a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_hcd_ddma.c b/drivers/amlogic/usb/dwc_otg/310/dwc_otg_hcd_ddma.c index 7acc2348a1be..6911e0482ed9 100644 --- a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_hcd_ddma.c +++ b/drivers/amlogic/usb/dwc_otg/310/dwc_otg_hcd_ddma.c @@ -39,8 +39,6 @@ #include "dwc_otg_hcd.h" #include "dwc_otg_regs.h" -extern bool microframe_schedule; - static inline uint8_t frame_list_idx(uint16_t frame) { return (frame & (MAX_FRLIST_EN_NUM - 1)); @@ -275,18 +273,10 @@ void dump_frame_list(dwc_otg_hcd_t * hcd) static void release_channel_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) { - dwc_irqflags_t flags; - dwc_spinlock_t *channel_lock = hcd->channel_lock; - dwc_hc_t *hc = qh->channel; - if (dwc_qh_is_non_per(qh)) { - DWC_SPINLOCK_IRQSAVE(channel_lock, &flags); - if (!microframe_schedule) + if (dwc_qh_is_non_per(qh)) hcd->non_periodic_channels--; else - hcd->available_host_channels++; - DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags); - } else update_frame_list(hcd, qh, 0); /* @@ -368,7 +358,7 @@ void dwc_otg_hcd_qh_free_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) release_channel_ddma(hcd, qh); if ((qh->ep_type == UE_ISOCHRONOUS || qh->ep_type == UE_INTERRUPT) - && (microframe_schedule || !hcd->periodic_channels) && hcd->frame_list) { + && !hcd->periodic_channels && hcd->frame_list) { per_sched_disable(hcd); frame_list_free(hcd); diff --git a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_hcd_if.h b/drivers/amlogic/usb/dwc_otg/310/dwc_otg_hcd_if.h old mode 100755 new mode 100644 index 3e448b512f70..75131817e979 --- a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_hcd_if.h +++ b/drivers/amlogic/usb/dwc_otg/310/dwc_otg_hcd_if.h @@ -79,6 +79,8 @@ struct dwc_otg_hcd_function_ops { dwc_otg_hcd_hub_info_from_urb_cb_t hub_info; dwc_otg_hcd_speed_from_urb_cb_t speed; dwc_otg_hcd_complete_urb_cb_t complete; + dwc_otg_hcd_complete_urb_cb_t complete_in_tasklet; + dwc_otg_hcd_complete_urb_cb_t hcd_isoc_complete; dwc_otg_hcd_get_b_hnp_enable get_b_hnp_enable; }; /** @} */ @@ -113,11 +115,6 @@ extern void dwc_otg_hcd_remove(dwc_otg_hcd_t * hcd); */ extern int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd); -/** This function is used to handle the fast interrupt - * - */ -extern void __attribute__ ((naked)) dwc_otg_hcd_handle_fiq(void); - /** * Returns private data set by * dwc_otg_hcd_set_priv_data function. diff --git a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_hcd_intr.c b/drivers/amlogic/usb/dwc_otg/310/dwc_otg_hcd_intr.c old mode 100755 new mode 100644 index 59a1ef591f13..d508b594c2f7 --- a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_hcd_intr.c +++ b/drivers/amlogic/usb/dwc_otg/310/dwc_otg_hcd_intr.c @@ -35,99 +35,38 @@ #include "dwc_otg_hcd.h" #include "dwc_otg_regs.h" -#include -#include -#include - - -extern bool microframe_schedule; - /** @file * This file contains the implementation of the HCD Interrupt handlers. */ -int fiq_done, int_done; - -#ifdef FIQ_DEBUG -char buffer[1000*16]; -int wptr; -void notrace _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) }; - - if(dbg_lvl & dbg_lvl_req || dbg_lvl == FIQDBG_ERR) - { - local_fiq_disable(); - 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_fiq_enable(); - } -} -#endif - /** This function handles interrupts for the HCD. */ int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd) { int retval = 0; - static int last_time; + dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if; gintsts_data_t gintsts; - gintmsk_data_t gintmsk; - haintmsk_data_t haintmsk; - #ifdef DEBUG dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs; #endif - - DWC_SPINLOCK(dwc_otg_hcd->lock); - - gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts); - gintmsk.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintmsk); - + if (dwc_otg_check_haps_status(core_if) == -1 ) { DWC_WARN("HAPS is disconnected"); - goto exit_handler_routine; + return retval; } - + /* Exit from ISR if core is hibernated */ if (core_if->hibernation_suspend == 1) { - goto exit_handler_routine; + return retval; } - + DWC_SPINLOCK(dwc_otg_hcd->lock); /* Check if HOST Mode */ if (dwc_otg_is_host_mode(core_if)) { - if (fiq_enable&&dwc_otg_hcd->core_if->use_fiq_flag) { - local_fiq_disable(); - /* Pull in from the FIQ's disabled mask */ - gintmsk.d32 = gintmsk.d32 | ~(dwc_otg_hcd->fiq_state->gintmsk_saved.d32); - dwc_otg_hcd->fiq_state->gintmsk_saved.d32 = ~0; - } - - if (fiq_fsm_enable && dwc_otg_hcd->core_if->use_fiq_flag && ( 0x0000FFFF & ~(dwc_otg_hcd->fiq_state->haintmsk_saved.b2.chint))) { - gintsts.b.hcintr = 1; - } - - /* Danger will robinson: fake a SOF if necessary */ - if (fiq_fsm_enable && dwc_otg_hcd->core_if->use_fiq_flag && (dwc_otg_hcd->fiq_state->gintmsk_saved.b.sofintr == 1)) { - gintsts.b.sofintr = 1; - } - gintsts.d32 &= gintmsk.d32; - - if (fiq_enable&&dwc_otg_hcd->core_if->use_fiq_flag) - local_fiq_enable(); - + gintsts.d32 = dwc_otg_read_core_intr(core_if); if (!gintsts.d32) { - goto exit_handler_routine; + DWC_SPINUNLOCK(dwc_otg_hcd->lock); + return 0; } - #ifdef DEBUG /* Don't print debug message in the interrupt handler on SOF */ #ifndef DEBUG_SOF @@ -144,6 +83,7 @@ int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd) "DWC OTG HCD Interrupt Detected gintsts&gintmsk=0x%08x\n", gintsts.d32); #endif + if (gintsts.b.sofintr) { retval |= dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd); } @@ -161,10 +101,7 @@ 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); @@ -196,50 +133,6 @@ int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd) #endif } - -exit_handler_routine: - if (fiq_enable && dwc_otg_hcd->core_if->use_fiq_flag) { - gintmsk_data_t gintmsk_new; - haintmsk_data_t haintmsk_new; - local_fiq_disable(); - gintmsk_new.d32 = *(volatile uint32_t *)&dwc_otg_hcd->fiq_state->gintmsk_saved.d32; - if(fiq_fsm_enable) - haintmsk_new.d32 = *(volatile uint32_t *)&dwc_otg_hcd->fiq_state->haintmsk_saved.d32; - else - haintmsk_new.d32 = 0x0000FFFF; - - /* The FIQ could have sneaked another interrupt in. If so, don't clear MPHI */ - if ((gintmsk_new.d32 == ~0) && (haintmsk_new.d32 == 0x0000FFFF)) { -#if 0 - DWC_WRITE_REG32(dwc_otg_hcd->fiq_state->mphi_regs.intstat, (1<<16)); - if (dwc_otg_hcd->fiq_state->mphi_int_count >= 50) { - fiq_print(FIQDBG_INT, dwc_otg_hcd->fiq_state, "MPHI CLR"); - DWC_WRITE_REG32(dwc_otg_hcd->fiq_state->mphi_regs.ctrl, ((1<<31) + (1<<16))); - while (!(DWC_READ_REG32(dwc_otg_hcd->fiq_state->mphi_regs.ctrl) & (1 << 17))) - ; - DWC_WRITE_REG32(dwc_otg_hcd->fiq_state->mphi_regs.ctrl, (1<<31)); - dwc_otg_hcd->fiq_state->mphi_int_count = 0; - } -#endif - int_done++; - } - haintmsk.d32 = DWC_READ_REG32(&core_if->host_if->host_global_regs->haintmsk); - /* Re-enable interrupts that the FIQ masked (first time round) */ - FIQ_WRITE(dwc_otg_hcd->fiq_state->dwc_regs_base + GINTMSK, gintmsk.d32); - local_fiq_enable(); - - if ((jiffies / HZ) > last_time) { - //dwc_otg_qh_t *qh; - //dwc_list_link_t *cur; - /* Once a second output the fiq and irq numbers, useful for debug */ - last_time = jiffies / HZ; - // DWC_WARN("np_kick=%d AHC=%d sched_frame=%d cur_frame=%d int_done=%d fiq_done=%d", - // dwc_otg_hcd->fiq_state->kick_np_queues, dwc_otg_hcd->available_host_channels, - // dwc_otg_hcd->fiq_state->next_sched_frame, hfnum.b.frnum, int_done, dwc_otg_hcd->fiq_state->fiq_done); - //printk(KERN_WARNING "Periodic queues:\n"); - } - } - DWC_SPINUNLOCK(dwc_otg_hcd->lock); return retval; } @@ -247,22 +140,20 @@ exit_handler_routine: #ifdef DWC_TRACK_MISSED_SOFS #warning Compiling code to track missed SOFs #define FRAME_NUM_ARRAY_SIZE 1000 - /** * This function is for debug only. */ -void track_missed_sofs(uint16_t curr_frame_number) +static inline void track_missed_sofs(uint16_t curr_frame_number) { - - static uint16_t last_frame_num = DWC_HFNUM_MAX_FRNUM; - static int dumped_frame_num_array = 0; static uint16_t frame_num_array[FRAME_NUM_ARRAY_SIZE]; static uint16_t last_frame_num_array[FRAME_NUM_ARRAY_SIZE]; static int frame_num_idx = 0; + static uint16_t last_frame_num = DWC_HFNUM_MAX_FRNUM; + static int dumped_frame_num_array = 0; if (frame_num_idx < FRAME_NUM_ARRAY_SIZE) { - if ((((last_frame_num + 1) & 0x3fff) != - curr_frame_number)&&(last_frame_num!=curr_frame_number)){ + if (((last_frame_num + 1) & DWC_HFNUM_MAX_FRNUM) != + curr_frame_number) { frame_num_array[frame_num_idx] = curr_frame_number; last_frame_num_array[frame_num_idx++] = last_frame_num; } @@ -289,12 +180,10 @@ void track_missed_sofs(uint16_t curr_frame_number) int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * hcd) { hfnum_data_t hfnum; - gintsts_data_t gintsts = { .d32 = 0 }; dwc_list_link_t *qh_entry; dwc_otg_qh_t *qh; dwc_otg_transaction_type_e tr_type; - int did_something = 0; - int32_t next_sched_frame = -1; + gintsts_data_t gintsts = {.d32 = 0 }; hfnum.d32 = DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hfnum); @@ -324,31 +213,17 @@ int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * hcd) */ DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_ready, &qh->qh_list_entry); - - did_something = 1; } - else - { - if(next_sched_frame < 0 || dwc_frame_num_le(qh->sched_frame, next_sched_frame)) - { - next_sched_frame = qh->sched_frame; - } - } } - if (fiq_enable&&hcd->core_if->use_fiq_flag) - hcd->fiq_state->next_sched_frame = next_sched_frame; - tr_type = dwc_otg_hcd_select_transactions(hcd); if (tr_type != DWC_OTG_TRANSACTION_NONE) { dwc_otg_hcd_queue_transactions(hcd, tr_type); - did_something = 1; } - /* Clear interrupt - but do not trample on the FIQ sof */ - if (!(fiq_fsm_enable&&hcd->core_if->use_fiq_flag)) { + /* Clear interrupt */ gintsts.b.sofintr = 1; DWC_WRITE_REG32(&hcd->core_if->core_global_regs->gintsts, gintsts.d32); - } + return 1; } @@ -638,24 +513,13 @@ int32_t dwc_otg_hcd_handle_hc_intr(dwc_otg_hcd_t * dwc_otg_hcd) { int i; int retval = 0; - haint_data_t haint = { .d32 = 0 } ; + haint_data_t haint; /* Clear appropriate bits in HCINTn to clear the interrupt bit in * GINTSTS */ - if (!(fiq_fsm_enable&&dwc_otg_hcd->core_if->use_fiq_flag)) haint.d32 = dwc_otg_read_host_all_channels_intr(dwc_otg_hcd->core_if); - // Overwrite with saved interrupts from fiq handler - if(fiq_fsm_enable&&dwc_otg_hcd->core_if->use_fiq_flag) - { - /* check the mask? */ - local_fiq_disable(); - haint.b2.chint |= ~(dwc_otg_hcd->fiq_state->haintmsk_saved.b2.chint); - dwc_otg_hcd->fiq_state->haintmsk_saved.b2.chint = ~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); @@ -754,7 +618,7 @@ static int update_urb_state_xfer_comp(dwc_hc_t * hc, && (urb->actual_length == urb->length) && !(urb->length % hc->max_packet)) { xfer_done = 0; - } else if (short_read || urb->actual_length >= urb->length) { + } else if (short_read || urb->actual_length == urb->length) { xfer_done = 1; urb->status = 0; }else if(urb->actual_length > urb->length){ @@ -831,7 +695,9 @@ update_isoc_urb_state(dwc_otg_hcd_t * hcd, dwc_otg_hcd_urb_t *urb = qtd->urb; dwc_otg_halt_status_e ret_val = halt_status; struct dwc_otg_hcd_iso_packet_desc *frame_desc; - +#if 0 + dwc_otg_hcd_urb_list_t * urb_list; +#endif frame_desc = &urb->iso_descs[qtd->isoc_frame_index]; switch (halt_status) { case DWC_OTG_HC_XFER_COMPLETE: @@ -883,12 +749,33 @@ update_isoc_urb_state(dwc_otg_hcd_t * hcd, DWC_ASSERT(1, "Unhandled _halt_status (%d)\n", halt_status); break; } - if (++qtd->isoc_frame_index == urb->packet_count) { + if ((++qtd->isoc_frame_index == urb->packet_count) ||(urb->qh_state == URB_STATE_DQUEUE)){ /* * urb->status is not used for isoc transfers. * The individual frame_desc statuses are used instead. */ - hcd->fops->complete(hcd, urb->priv, urb, 0); + +#if 0 + urb_list = DWC_ALLOC(sizeof(dwc_otg_hcd_urb_list_t)); + if (urb_list == NULL) { + DWC_ASSERT(1, "No memory alloc in update_isoc_urb_state\n"); + } + urb_list->urb = urb; + DWC_SPINLOCK(hcd->isoc_comp_urbs_lock); + DWC_LIST_INSERT_TAIL(&hcd->isoc_comp_urbs_list, &urb_list->urb_list_entry); + DWC_SPINUNLOCK(hcd->isoc_comp_urbs_lock); +#else + int i; + for(i = 0; i < MAX_EPS_CHANNELS; i++){ + if(hcd->isoc_comp_urbs[i] == NULL){ + hcd->isoc_comp_urbs[i] = urb->priv; + break; + } + } + + hcd->fops->hcd_isoc_complete(hcd,urb->priv,urb,0); + DWC_TASK_SCHEDULE(hcd->isoc_complete_tasklet); +#endif ret_val = DWC_OTG_HC_XFER_URB_COMPLETE; } else { ret_val = DWC_OTG_HC_XFER_COMPLETE; @@ -946,22 +833,9 @@ static void release_channel(dwc_otg_hcd_t * hcd, { dwc_otg_transaction_type_e tr_type; int free_qtd; - dwc_irqflags_t flags; - dwc_spinlock_t *channel_lock = hcd->channel_lock; - int hog_port = 0; - - DWC_DEBUGPL(DBG_HCDV, " %s: channel %d, halt_status %d, xfer_len %d\n", - __func__, hc->hc_num, halt_status, hc->xfer_len); - - if(fiq_fsm_enable && hcd->core_if->use_fiq_flag && hc->do_split) { - if(!hc->ep_is_in && hc->ep_type == UE_ISOCHRONOUS) { - if(hc->xact_pos == DWC_HCSPLIT_XACTPOS_MID || - hc->xact_pos == DWC_HCSPLIT_XACTPOS_BEGIN) { - hog_port = 0; - } - } - } + DWC_DEBUGPL(DBG_HCDV, " %s: channel %d, halt_status %d\n", + __func__, hc->hc_num, halt_status); switch (halt_status) { case DWC_OTG_HC_XFER_URB_COMPLETE: @@ -1015,12 +889,9 @@ cleanup: * function clears the channel interrupt enables and conditions, so * there's no need to clear the Channel Halted interrupt separately. */ - if (fiq_fsm_enable && hcd->core_if->use_fiq_flag && hcd->fiq_state->channel[hc->hc_num].fsm != FIQ_PASSTHROUGH) - dwc_otg_cleanup_fiq_channel(hcd, hc->hc_num); dwc_otg_hc_cleanup(hcd->core_if, hc); DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, hc, hc_list_entry); - if (!microframe_schedule) { switch (hc->ep_type) { case DWC_OTG_EP_TYPE_CONTROL: case DWC_OTG_EP_TYPE_BULK: @@ -1035,13 +906,6 @@ cleanup: */ break; } - } else { - - DWC_SPINLOCK_IRQSAVE(channel_lock, &flags); - hcd->available_host_channels++; - fiq_print(FIQDBG_INT, hcd->fiq_state, "AHC = %d ", hcd->available_host_channels); - DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags); - } /* Try to queue more transfers now that there's a free channel. */ tr_type = dwc_otg_hcd_select_transactions(hcd); @@ -1256,6 +1120,8 @@ static int32_t handle_hc_xfercomp_intr(dwc_otg_hcd_t * hcd, */ if (hc->qh->do_split) { + if(hc->ep_type == DWC_OTG_EP_TYPE_INTR) + hcd->ssplit_lock = 0; if ((hc->ep_type == DWC_OTG_EP_TYPE_ISOC) && hc->ep_is_in && hcd->core_if->dma_enable) { if (qtd->complete_split @@ -1378,6 +1244,9 @@ static int32_t handle_hc_stall_intr(dwc_otg_hcd_t * hcd, goto handle_stall_done; } + if(pipe_type == UE_INTERRUPT) + hcd->ssplit_lock = 0; + if (pipe_type == UE_CONTROL) { hcd->fops->complete(hcd, urb->priv, urb, -DWC_E_PIPE); } @@ -1457,17 +1326,6 @@ static int32_t handle_hc_nak_intr(dwc_otg_hcd_t * hcd, DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " "NAK Received--\n", hc->hc_num); - /* - * When we get bulk NAKs then remember this so we holdoff on this qh until - * the beginning of the next frame - */ - switch(dwc_otg_hcd_get_pipe_type(&qtd->urb->pipe_info)) { - case UE_BULK: - case UE_CONTROL: - if (nak_holdoff && qtd->qh->do_split) - hc->qh->nak_frame = dwc_otg_hcd_get_frame_number(hcd); - } - /* * Handle NAK for IN/OUT SSPLIT/CSPLIT transfers, bulk, control, and * interrupt. Re-start the SSPLIT transfer. @@ -1476,6 +1334,11 @@ static int32_t handle_hc_nak_intr(dwc_otg_hcd_t * hcd, if (hc->complete_split) { qtd->error_count = 0; } + + if((hcd->ssplit_lock == dwc_otg_hcd_get_dev_addr(&qtd->urb->pipe_info)) && + (dwc_otg_hcd_get_pipe_type(&qtd->urb->pipe_info) == UE_INTERRUPT)) + hcd->ssplit_lock = 0; + qtd->complete_split = 0; halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NAK); goto handle_nak_done; @@ -1490,11 +1353,7 @@ static int32_t handle_hc_nak_intr(dwc_otg_hcd_t * hcd, * transfers in DMA mode for the sole purpose of * resetting the error count after a transaction error * occurs. The core will continue transferring data. - * Disable other interrupts unmasked for the same - * reason. */ - disable_hc_int(hc_regs, datatglerr); - disable_hc_int(hc_regs, ack); qtd->error_count = 0; goto handle_nak_done; } @@ -1606,15 +1465,6 @@ static int32_t handle_hc_ack_intr(dwc_otg_hcd_t * hcd, halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_ACK); } } else { - /* - * An unmasked ACK on a non-split DMA transaction is - * for the sole purpose of resetting error counts. Disable other - * interrupts unmasked for the same reason. - */ - if(hcd->core_if->dma_enable) { - disable_hc_int(hc_regs, datatglerr); - disable_hc_int(hc_regs, nak); - } qtd->error_count = 0; if (hc->qh->ping_state) { @@ -1677,10 +1527,8 @@ 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) || - (fiq_fsm_enable&&hcd->core_if->use_fiq_flag)) { + dwc_full_frame_num(hc->qh->sched_frame)) { /* * No longer in the same full speed frame. * Treat this as a transaction error. @@ -1695,6 +1543,7 @@ static int32_t handle_hc_nyet_intr(dwc_otg_hcd_t * hcd, qtd->error_count++; #endif qtd->complete_split = 0; + hcd->ssplit_lock = 0; halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_XACT_ERR); /** @todo add support for isoc release */ @@ -1899,8 +1748,10 @@ static int32_t handle_hc_xacterr_intr(dwc_otg_hcd_t * hcd, break; case UE_INTERRUPT: qtd->error_count++; - if (hc->do_split && hc->complete_split) { + if (hc->do_split){ + if(hc->complete_split) qtd->complete_split = 0; + hcd->ssplit_lock = 0; } halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_XACT_ERR); break; @@ -1967,28 +1818,13 @@ static int32_t handle_hc_datatglerr_intr(dwc_otg_hcd_t * hcd, dwc_otg_qtd_t * qtd) { DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " - "Data Toggle Error on %s transfer--\n", - hc->hc_num, (hc->ep_is_in ? "IN" : "OUT")); + "Data Toggle Error--\n", hc->hc_num); - /* Data toggles on split transactions cause the hc to halt. - * restart transfer */ - if(hc->qh->do_split) - { - qtd->error_count++; - dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd); - update_urb_state_xfer_intr(hc, hc_regs, - qtd->urb, qtd, DWC_OTG_HC_XFER_XACT_ERR); - halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_XACT_ERR); - } else if (hc->ep_is_in) { - /* An unmasked data toggle error on a non-split DMA transaction is - * for the sole purpose of resetting error counts. Disable other - * interrupts unmasked for the same reason. - */ - if(hcd->core_if->dma_enable) { - disable_hc_int(hc_regs, ack); - disable_hc_int(hc_regs, nak); - } + if (hc->ep_is_in) { qtd->error_count = 0; + } else { + DWC_ERROR("Data Toggle Error on OUT transfer," + "channel %d\n", hc->hc_num); } disable_hc_int(hc_regs, datatglerr); @@ -2141,8 +1977,6 @@ static void handle_hc_chhltd_intr_dma(dwc_otg_hcd_t * hcd, handle_hc_babble_intr(hcd, hc, hc_regs, qtd); } else if (hcint.b.frmovrun) { handle_hc_frmovrun_intr(hcd, hc, hc_regs, qtd); - } else if (hcint.b.datatglerr) { - handle_hc_datatglerr_intr(hcd, hc, hc_regs, qtd); } else if (!out_nak_enh) { if (hcint.b.nyet) { /* @@ -2182,6 +2016,8 @@ static void handle_hc_chhltd_intr_dma(dwc_otg_hcd_t * hcd, ("%s: Halt channel %d (assume incomplete periodic transfer)\n", __func__, hc->hc_num); #endif + if (hc->do_split && (hc->ep_type == DWC_OTG_EP_TYPE_INTR)) + hcd->ssplit_lock = 0; halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_PERIODIC_INCOMPLETE); } else { @@ -2192,24 +2028,14 @@ static void handle_hc_chhltd_intr_dma(dwc_otg_hcd_t * hcd, DWC_READ_REG32(&hcd-> core_if->core_global_regs-> gintsts)); - /* Failthrough: use 3-strikes rule */ - qtd->error_count++; - dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd); - update_urb_state_xfer_intr(hc, hc_regs, - qtd->urb, qtd, DWC_OTG_HC_XFER_XACT_ERR); - halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_XACT_ERR); + clear_hc_int(hc_regs, chhltd); } } } else { DWC_PRINTF("NYET/NAK/ACK/other in non-error case, 0x%08x\n", hcint.d32); - /* Failthrough: use 3-strikes rule */ - qtd->error_count++; - dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd); - update_urb_state_xfer_intr(hc, hc_regs, - qtd->urb, qtd, DWC_OTG_HC_XFER_XACT_ERR); - halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_XACT_ERR); + clear_hc_int(hc_regs, chhltd); } } @@ -2246,367 +2072,6 @@ static int32_t handle_hc_chhltd_intr(dwc_otg_hcd_t * hcd, return 1; } - -/** - * dwc_otg_fiq_unmangle_isoc() - Update the iso_frame_desc structure on - * FIQ transfer completion - * @hcd: Pointer to dwc_otg_hcd struct - * @num: Host channel number - * - * 1. Un-mangle the status as recorded in each iso_frame_desc status - * 2. Copy it from the dwc_otg_urb into the real URB - */ -void dwc_otg_fiq_unmangle_isoc(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh, dwc_otg_qtd_t *qtd, uint32_t num) -{ - struct dwc_otg_hcd_urb *dwc_urb = qtd->urb; - int nr_frames = dwc_urb->packet_count; - int i; - hcint_data_t frame_hcint; - - for (i = 0; i < nr_frames; i++) { - frame_hcint.d32 = dwc_urb->iso_descs[i].status; - if (frame_hcint.b.xfercomp) { - dwc_urb->iso_descs[i].status = 0; - dwc_urb->actual_length += dwc_urb->iso_descs[i].actual_length; - } else if (frame_hcint.b.frmovrun) { - if (qh->ep_is_in) - dwc_urb->iso_descs[i].status = -DWC_E_NO_STREAM_RES; - else - dwc_urb->iso_descs[i].status = -DWC_E_COMMUNICATION; - dwc_urb->error_count++; - dwc_urb->iso_descs[i].actual_length = 0; - } else if (frame_hcint.b.xacterr) { - dwc_urb->iso_descs[i].status = -DWC_E_PROTOCOL; - dwc_urb->error_count++; - dwc_urb->iso_descs[i].actual_length = 0; - } else if (frame_hcint.b.bblerr) { - dwc_urb->iso_descs[i].status = -DWC_E_OVERFLOW; - dwc_urb->error_count++; - dwc_urb->iso_descs[i].actual_length = 0; - } else { - /* Something went wrong */ - dwc_urb->iso_descs[i].status = -1; - dwc_urb->iso_descs[i].actual_length = 0; - dwc_urb->error_count++; - } - } - //printk_ratelimited(KERN_INFO "%s: HS isochronous of %d/%d frames with %d errors complete\n", - // __FUNCTION__, i, dwc_urb->packet_count, dwc_urb->error_count); - hcd->fops->complete(hcd, dwc_urb->priv, dwc_urb, 0); - release_channel(hcd, qh->channel, qtd, DWC_OTG_HC_XFER_URB_COMPLETE); -} - -/** - * dwc_otg_fiq_unsetup_per_dma() - Remove data from bounce buffers for split transactions - * @hcd: Pointer to dwc_otg_hcd struct - * @num: Host channel number - * - * Copies data from the FIQ bounce buffers into the URB's transfer buffer. Does not modify URB state. - * Returns total length of data or -1 if the buffers were not used. - * - */ -int dwc_otg_fiq_unsetup_per_dma(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh, dwc_otg_qtd_t *qtd, uint32_t num) -{ - dwc_hc_t *hc = qh->channel; - struct fiq_dma_blob *blob = hcd->fiq_dmab; - struct fiq_channel_state *st = &hcd->fiq_state->channel[num]; - uint8_t *ptr = NULL; - int index = 0, len = 0; - int i = 0; - if (hc->ep_is_in) { - /* Copy data out of the DMA bounce buffers to the URB's buffer. - * The align_buf is ignored as this is ignored on FSM enqueue. */ - ptr = qtd->urb->buf; - if (qh->ep_type == UE_ISOCHRONOUS) { - /* Isoc IN transactions - grab the offset of the iso_frame_desc into the URB transfer buffer */ - index = qtd->isoc_frame_index; - ptr += qtd->urb->iso_descs[index].offset; - } else { - /* Need to increment by actual_length for interrupt IN */ - ptr += qtd->urb->actual_length; - } - - for (i = 0; i < st->dma_info.index; i++) { - len += st->dma_info.slot_len[i]; - dwc_memcpy(ptr, &blob->channel[num].index[i].buf[0], st->dma_info.slot_len[i]); - ptr += st->dma_info.slot_len[i]; - } - return len; - } else { - /* OUT endpoints - nothing to do. */ - return -1; - } - -} -/** - * dwc_otg_hcd_handle_hc_fsm() - handle an unmasked channel interrupt - * from a channel handled in the FIQ - * @hcd: Pointer to dwc_otg_hcd struct - * @num: Host channel number - * - * If a host channel interrupt was received by the IRQ and this was a channel - * used by the FIQ, the execution flow for transfer completion is substantially - * different from the normal (messy) path. This function and its friends handles - * channel cleanup and transaction completion from a FIQ transaction. - */ -int32_t dwc_otg_hcd_handle_hc_fsm(dwc_otg_hcd_t *hcd, uint32_t num) -{ - struct fiq_channel_state *st = &hcd->fiq_state->channel[num]; - dwc_hc_t *hc = hcd->hc_ptr_array[num]; - dwc_otg_qtd_t *qtd = DWC_CIRCLEQ_FIRST(&hc->qh->qtd_list); - dwc_otg_qh_t *qh = hc->qh; - dwc_otg_hc_regs_t *hc_regs = hcd->core_if->host_if->hc_regs[num]; - hcint_data_t hcint = hcd->fiq_state->channel[num].hcint_copy; - int hostchannels = 0; - int ret = 0; - fiq_print(FIQDBG_INT, hcd->fiq_state, "OUT %01d %01d ", num , st->fsm); - - hostchannels = hcd->available_host_channels; - switch (st->fsm) { - case FIQ_TEST: - break; - - case FIQ_DEQUEUE_ISSUED: - /* hc_halt was called. QTD no longer exists. */ - /* TODO: for a nonperiodic split transaction, need to issue a - * CLEAR_TT_BUFFER hub command if we were in the start-split phase. - */ - release_channel(hcd, hc, NULL, hc->halt_status); - ret = 1; - break; - - case FIQ_NP_SPLIT_DONE: - /* Nonperiodic transaction complete. */ - if (!hc->ep_is_in) { - qtd->ssplit_out_xfer_count = hc->xfer_len; - } - if (hcint.b.xfercomp) { - handle_hc_xfercomp_intr(hcd, hc, hc_regs, qtd); - } else if (hcint.b.nak) { - handle_hc_nak_intr(hcd, hc, hc_regs, qtd); - } - ret = 1; - break; - - case FIQ_NP_SPLIT_HS_ABORTED: - /* A HS abort is a 3-strikes on the HS bus at any point in the transaction. - * Normally a CLEAR_TT_BUFFER hub command would be required: we can't do that - * because there's no guarantee which order a non-periodic split happened in. - * We could end up clearing a perfectly good transaction out of the buffer. - */ - if (hcint.b.xacterr) { - qtd->error_count += st->nr_errors; - handle_hc_xacterr_intr(hcd, hc, hc_regs, qtd); - } else if (hcint.b.ahberr) { - handle_hc_ahberr_intr(hcd, hc, hc_regs, qtd); - } else { - local_fiq_disable(); - BUG(); - } - break; - - case FIQ_NP_SPLIT_LS_ABORTED: - /* A few cases can cause this - either an unknown state on a SSPLIT or - * STALL/data toggle error response on a CSPLIT */ - if (hcint.b.stall) { - handle_hc_stall_intr(hcd, hc, hc_regs, qtd); - } else if (hcint.b.datatglerr) { - handle_hc_datatglerr_intr(hcd, hc, hc_regs, qtd); - } else if (hcint.b.bblerr) { - handle_hc_babble_intr(hcd, hc, hc_regs, qtd); - } else if (hcint.b.ahberr) { - handle_hc_ahberr_intr(hcd, hc, hc_regs, qtd); - } else { - local_fiq_disable(); - BUG(); - } - break; - - case FIQ_PER_SPLIT_DONE: - /* Isoc IN or Interrupt IN/OUT */ - - /* Flow control here is different from the normal execution by the driver. - * We need to completely ignore most of the driver's method of handling - * split transactions and do it ourselves. - */ - if (hc->ep_type == UE_INTERRUPT) { - if (hcint.b.nak) { - handle_hc_nak_intr(hcd, hc, hc_regs, qtd); - } else if (hc->ep_is_in) { - int len; - len = dwc_otg_fiq_unsetup_per_dma(hcd, hc->qh, qtd, num); - //printk(KERN_NOTICE "FIQ Transaction: hc=%d len=%d urb_len = %d\n", num, len, qtd->urb->length); - qtd->urb->actual_length += len; - if (qtd->urb->actual_length >= qtd->urb->length) { - qtd->urb->status = 0; - hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, qtd->urb->status); - release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE); - } else { - /* Interrupt transfer not complete yet - is it a short read? */ - if (len < hc->max_packet) { - /* Interrupt transaction complete */ - qtd->urb->status = 0; - hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, qtd->urb->status); - release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE); - } else { - /* Further transactions required */ - release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_COMPLETE); - } - } - } else { - /* Interrupt OUT complete. */ - dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd); - qtd->urb->actual_length += hc->xfer_len; - if (qtd->urb->actual_length >= qtd->urb->length) { - qtd->urb->status = 0; - hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, qtd->urb->status); - release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE); - } else { - release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_COMPLETE); - } - } - } else { - /* ISOC IN complete. */ - struct dwc_otg_hcd_iso_packet_desc *frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index]; - int len = 0; - /* Record errors, update qtd. */ - if (st->nr_errors) { - frame_desc->actual_length = 0; - frame_desc->status = -DWC_E_PROTOCOL; - } else { - frame_desc->status = 0; - /* Unswizzle dma */ - len = dwc_otg_fiq_unsetup_per_dma(hcd, qh, qtd, num); - frame_desc->actual_length = len; - } - qtd->isoc_frame_index++; - if (qtd->isoc_frame_index == qtd->urb->packet_count) { - hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0); - release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE); - } else { - release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_COMPLETE); - } - } - break; - - case FIQ_PER_ISO_OUT_DONE: { - struct dwc_otg_hcd_iso_packet_desc *frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index]; - /* Record errors, update qtd. */ - if (st->nr_errors) { - frame_desc->actual_length = 0; - frame_desc->status = -DWC_E_PROTOCOL; - } else { - frame_desc->status = 0; - frame_desc->actual_length = frame_desc->length; - } - qtd->isoc_frame_index++; - qtd->isoc_split_offset = 0; - if (qtd->isoc_frame_index == qtd->urb->packet_count) { - hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0); - release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE); - } else { - release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_COMPLETE); - } - } - break; - - case FIQ_PER_SPLIT_NYET_ABORTED: - /* Doh. lost the data. */ - printk_ratelimited(KERN_INFO "Transfer to device %d endpoint 0x%x frame %d failed " - "- FIQ reported NYET. Data may have been lost.\n", - hc->dev_addr, hc->ep_num, dwc_otg_hcd_get_frame_number(hcd) >> 3); - if (hc->ep_type == UE_ISOCHRONOUS) { - struct dwc_otg_hcd_iso_packet_desc *frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index]; - /* Record errors, update qtd. */ - frame_desc->actual_length = 0; - frame_desc->status = -DWC_E_PROTOCOL; - qtd->isoc_frame_index++; - qtd->isoc_split_offset = 0; - if (qtd->isoc_frame_index == qtd->urb->packet_count) { - hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0); - release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE); - } else { - release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_COMPLETE); - } - } else { - release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NO_HALT_STATUS); - } - break; - - case FIQ_HS_ISOC_DONE: - /* The FIQ has performed a whole pile of isochronous transactions. - * The status is recorded as the interrupt state should the transaction - * fail. - */ - dwc_otg_fiq_unmangle_isoc(hcd, qh, qtd, num); - break; - - case FIQ_PER_SPLIT_LS_ABORTED: - if (hcint.b.xacterr) { - /* Hub has responded with an ERR packet. Device - * has been unplugged or the port has been disabled. - * TODO: need to issue a reset to the hub port. */ - qtd->error_count += 3; - handle_hc_xacterr_intr(hcd, hc, hc_regs, qtd); - } else if (hcint.b.stall) { - handle_hc_stall_intr(hcd, hc, hc_regs, qtd); - } else if (hcint.b.bblerr) { - handle_hc_babble_intr(hcd, hc, hc_regs, qtd); - } else { - printk_ratelimited(KERN_INFO "Transfer to device %d endpoint 0x%x failed " - "- FIQ reported FSM=%d. Data may have been lost.\n", - st->fsm, hc->dev_addr, hc->ep_num); - release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NO_HALT_STATUS); - } - break; - - case FIQ_PER_SPLIT_HS_ABORTED: - /* Either the SSPLIT phase suffered transaction errors or something - * unexpected happened. - */ - qtd->error_count += 3; - handle_hc_xacterr_intr(hcd, hc, hc_regs, qtd); - release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NO_HALT_STATUS); - break; - - case FIQ_PER_SPLIT_TIMEOUT: - /* Couldn't complete in the nominated frame */ - printk(KERN_INFO "Transfer to device %d endpoint 0x%x frame %d failed " - "- FIQ timed out. Data may have been lost.\n", - hc->dev_addr, hc->ep_num, dwc_otg_hcd_get_frame_number(hcd) >> 3); - if (hc->ep_type == UE_ISOCHRONOUS) { - struct dwc_otg_hcd_iso_packet_desc *frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index]; - /* Record errors, update qtd. */ - frame_desc->actual_length = 0; - if (hc->ep_is_in) { - frame_desc->status = -DWC_E_NO_STREAM_RES; - } else { - frame_desc->status = -DWC_E_COMMUNICATION; - } - qtd->isoc_frame_index++; - if (qtd->isoc_frame_index == qtd->urb->packet_count) { - hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0); - release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE); - } else { - release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_COMPLETE); - } - } else { - release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NO_HALT_STATUS); - } - break; - - default: - local_fiq_disable(); - DWC_WARN("unexpected state received on hc=%d fsm=%d", hc->hc_num, st->fsm); - BUG(); - } - //if (hostchannels != hcd->available_host_channels) { - /* should have incremented by now! */ - // BUG(); -// } - return ret; -} - /** Handles interrupt for a specific Host Channel */ int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd, uint32_t num) { @@ -2621,38 +2086,8 @@ int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd, uint32_t num) hc = dwc_otg_hcd->hc_ptr_array[num]; hc_regs = dwc_otg_hcd->core_if->host_if->hc_regs[num]; - if(hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE) { - /* We are responding to a channel disable. Driver - * state is cleared - our qtd has gone away. - */ - release_channel(dwc_otg_hcd, hc, NULL, hc->halt_status); - return 1; - } qtd = DWC_CIRCLEQ_FIRST(&hc->qh->qtd_list); - /* - * FSM mode: Check to see if this is a HC interrupt from a channel handled by the FIQ. - * Execution path is fundamentally different for the channels after a FIQ has completed - * a split transaction. - */ - if (fiq_fsm_enable&&dwc_otg_hcd->core_if->use_fiq_flag) { - switch (dwc_otg_hcd->fiq_state->channel[num].fsm) { - case FIQ_PASSTHROUGH: - break; - case FIQ_PASSTHROUGH_ERRORSTATE: - /* Hook into the error count */ - fiq_print(FIQDBG_ERR, dwc_otg_hcd->fiq_state, "HCDERR%02d", num); - if (!dwc_otg_hcd->fiq_state->channel[num].nr_errors) { - qtd->error_count = 0; - fiq_print(FIQDBG_ERR, dwc_otg_hcd->fiq_state, "RESET "); - } - break; - default: - dwc_otg_hcd_handle_hc_fsm(dwc_otg_hcd, num); - return 1; - } - } - hcint.d32 = DWC_READ_REG32(&hc_regs->hcint); hcintmsk.d32 = DWC_READ_REG32(&hc_regs->hcintmsk); DWC_DEBUGPL(DBG_HCDV, @@ -2689,7 +2124,6 @@ int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd, uint32_t num) retval |= handle_hc_nak_intr(dwc_otg_hcd, hc, hc_regs, qtd); } if (hcint.b.ack) { - if(!hcint.b.chhltd) retval |= handle_hc_ack_intr(dwc_otg_hcd, hc, hc_regs, qtd); } if (hcint.b.nyet) { diff --git a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_hcd_linux.c b/drivers/amlogic/usb/dwc_otg/310/dwc_otg_hcd_linux.c index 521cb7a2b57f..2c3f83c38e9a 100644 --- a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_hcd_linux.c +++ b/drivers/amlogic/usb/dwc_otg/310/dwc_otg_hcd_linux.c @@ -50,10 +50,7 @@ #include #include #include -#include #include -#include -#include #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) #include <../drivers/usb/core/hcd.h> #else @@ -64,12 +61,6 @@ #include "dwc_otg_dbg.h" #include "dwc_otg_driver.h" #include "dwc_otg_hcd.h" - -extern unsigned char _dwc_otg_fiq_stub, _dwc_otg_fiq_stub_end; - -DEFINE_PER_CPU(void *, fiq_stack_cpu); -static DEFINE_MUTEX(fiq_lock); - /** * Gets the endpoint number from a _bEndpointAddress argument. The endpoint is * qualified with its direction (possible 32 endpoints per device). @@ -79,8 +70,6 @@ static DEFINE_MUTEX(fiq_lock); static const char dwc_otg_hcd_name[] = "dwc_otg_hcd"; -extern bool fiq_enable; - /** @name Linux HC Driver API Functions */ /** @{ */ static int urb_enqueue(struct usb_hcd *hcd, @@ -234,6 +223,77 @@ static void free_bus_bandwidth(struct usb_hcd *hcd, uint32_t bw, hcd_to_bus(hcd)->bandwidth_int_reqs--; } } +int _hcd_isoc_complete(dwc_otg_hcd_t * hcd,void *urb_handle, + dwc_otg_hcd_urb_t * dwc_otg_urb, int32_t status) +{ + struct urb *urb = (struct urb *)urb_handle; + + if(dwc_otg_urb->qh_state == URB_STATE_DQUEUE) + status = -ENOENT; + + urb->actual_length = dwc_otg_urb->actual_length; + /* Convert status value. */ + switch (status) { + case -DWC_E_PROTOCOL: + status = -EPROTO; + break; + case -DWC_E_IN_PROGRESS: + status = -EINPROGRESS; + break; + case -DWC_E_PIPE: + status = -EPIPE; + break; + case -DWC_E_IO: + status = -EIO; + break; + case -DWC_E_TIMEOUT: + status = -ETIMEDOUT; + break; + case -DWC_E_OVERFLOW: + status = -EOVERFLOW; + break; + default: + if (status) { + printk(KERN_DEBUG "%s:Uknown urb status %d\n",__func__, status); + + } + } + + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { + int i; + + urb->error_count = dwc_otg_hcd_urb_get_error_count(dwc_otg_urb); + for (i = 0; i < urb->number_of_packets; ++i) { + urb->iso_frame_desc[i].actual_length = dwc_otg_urb->iso_descs[i].actual_length; + urb->iso_frame_desc[i].status = dwc_otg_urb->iso_descs[i].status; + } + } + + urb->status = status; + + if (!status) { + if ((urb->transfer_flags & URB_SHORT_NOT_OK) && + (urb->actual_length < urb->transfer_buffer_length)) { + urb->status = -EREMOTEIO; + } + } + + if ((usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) || + (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) { + struct usb_host_endpoint *ep = dwc_urb_to_endpoint(urb); + if (ep) { + free_bus_bandwidth(dwc_otg_hcd_to_hcd(hcd), + dwc_otg_hcd_get_ep_bandwidth(hcd, + ep->hcpriv), + urb); + } + } + + + DWC_FREE(dwc_otg_urb); + + return 0; +} /** * Sets the final status of an URB and returns it to the device driver. Any * required cleanup of the URB is performed. @@ -242,8 +302,6 @@ static int _complete(dwc_otg_hcd_t * hcd, void *urb_handle, dwc_otg_hcd_urb_t * dwc_otg_urb, int32_t status) { struct urb *urb = (struct urb *)urb_handle; - urb_tq_entry_t *new_entry; - int rc = 0; #ifdef DEBUG if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) { DWC_PRINTF("%s: urb %p, device %d, ep %d %s, status=%d\n", @@ -259,7 +317,7 @@ static int _complete(dwc_otg_hcd_t * hcd, void *urb_handle, } } #endif - new_entry = DWC_ALLOC_ATOMIC(sizeof(urb_tq_entry_t)); + urb->actual_length = dwc_otg_hcd_urb_get_actual_length(dwc_otg_urb); /* Convert status value. */ switch (status) { @@ -304,6 +362,108 @@ static int _complete(dwc_otg_hcd_t * hcd, void *urb_handle, } } + urb->status = status; + if (!status) { + if ((urb->transfer_flags & URB_SHORT_NOT_OK) && + (urb->actual_length < urb->transfer_buffer_length)) { + urb->status = -EREMOTEIO; + } + } + + if ((usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) || + (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) { + struct usb_host_endpoint *ep = dwc_urb_to_endpoint(urb); + if (ep) { + free_bus_bandwidth(dwc_otg_hcd_to_hcd(hcd), + dwc_otg_hcd_get_ep_bandwidth(hcd, + ep->hcpriv), + urb); + } + } +#if 0 + usb_hcd_unlink_urb_from_ep(dwc_otg_hcd_to_hcd(hcd), urb); +#endif + DWC_FREE(dwc_otg_urb); + dwc_otg_urb = NULL; + + DWC_SPINUNLOCK(hcd->lock); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) + usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb); +#else + usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb, status); +#endif + DWC_SPINLOCK(hcd->lock); + + return 0; +} + +/*copy from _complete,not use spinlock*/ +/** + * Sets the final status of an URB and returns it to the device driver. Any + * required cleanup of the URB is performed. + */ +int _complete_in_tasklet(dwc_otg_hcd_t * hcd, void *urb_handle, + dwc_otg_hcd_urb_t * dwc_otg_urb, int32_t status) +{ + struct urb *urb = (struct urb *)urb_handle; +#if 0 +#ifdef DEBUG + if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) { + DWC_PRINTF("%s: urb %p, device %d, ep %d %s, status=%d\n", + __func__, urb, usb_pipedevice(urb->pipe), + usb_pipeendpoint(urb->pipe), + usb_pipein(urb->pipe) ? "IN" : "OUT", status); + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { + int i; + for (i = 0; i < urb->number_of_packets; i++) { + DWC_PRINTF(" ISO Desc %d status: %d\n", + i, urb->iso_frame_desc[i].status); + } + } + } +#endif + + urb->actual_length = dwc_otg_hcd_urb_get_actual_length(dwc_otg_urb); + /* Convert status value. */ + switch (status) { + case -DWC_E_PROTOCOL: + status = -EPROTO; + break; + case -DWC_E_IN_PROGRESS: + status = -EINPROGRESS; + break; + case -DWC_E_PIPE: + status = -EPIPE; + break; + case -DWC_E_IO: + status = -EIO; + break; + case -DWC_E_TIMEOUT: + status = -ETIMEDOUT; + break; + case -DWC_E_OVERFLOW: + status = -EOVERFLOW; + break; + default: + if (status) { + DWC_PRINTF("Uknown urb status %d\n", status); + + } + } + + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { + int i; + + urb->error_count = dwc_otg_hcd_urb_get_error_count(dwc_otg_urb); + for (i = 0; i < urb->number_of_packets; ++i) { + urb->iso_frame_desc[i].actual_length = + dwc_otg_hcd_urb_get_iso_desc_actual_length + (dwc_otg_urb, i); + urb->iso_frame_desc[i].status = + dwc_otg_hcd_urb_get_iso_desc_status(dwc_otg_urb, i); + } + } + urb->status = status; urb->hcpriv = NULL; if (!status) { @@ -323,37 +483,19 @@ static int _complete(dwc_otg_hcd_t * hcd, void *urb_handle, urb); } } +#if 0 + usb_hcd_unlink_urb_from_ep(dwc_otg_hcd_to_hcd(hcd), urb); +#endif DWC_FREE(dwc_otg_urb); - if (!new_entry) { - DWC_ERROR("dwc_otg_hcd: complete: cannot allocate URB TQ entry\n"); - urb->status = -EPROTO; - /* don't schedule the tasklet - - * directly return the packet here with error. */ -#if 0 - usb_hcd_unlink_urb_from_ep(dwc_otg_hcd_to_hcd(hcd), urb); #endif - - DWC_SPINUNLOCK(hcd->lock); + //DWC_SPINUNLOCK(hcd->lock); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) - usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb); + usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb); #else - usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb, urb->status); + usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb, urb->status); #endif - DWC_SPINLOCK(hcd->lock); - } else { - new_entry->urb = urb; -#if 0 - rc = usb_hcd_check_unlink_urb(dwc_otg_hcd_to_hcd(hcd), urb, urb->status); - if(0 == rc) { - usb_hcd_unlink_urb_from_ep(dwc_otg_hcd_to_hcd(hcd), urb); - } -#endif - if(0 == rc) { - DWC_TAILQ_INSERT_TAIL(&hcd->completed_urb_list, new_entry, - urb_tq_entries); - DWC_TASK_HI_SCHEDULE(hcd->completion_tasklet); - } - } + //DWC_SPINLOCK(hcd->lock); + return 0; } @@ -363,25 +505,11 @@ static struct dwc_otg_hcd_function_ops hcd_fops = { .hub_info = _hub_info, .speed = _speed, .complete = _complete, - //.complete_in_tasklet = _complete_in_tasklet, - //.hcd_isoc_complete = _hcd_isoc_complete, + .complete_in_tasklet = _complete_in_tasklet, + .hcd_isoc_complete = _hcd_isoc_complete, .get_b_hnp_enable = _get_b_hnp_enable, }; -static struct fiq_handler fh = { - .name = "usb_fiq", -}; - -extern void __fiq_ll_setup(long r8, long r9, long fp, void *sp); -static void fiq_setup_helper(void *regs) -{ - struct pt_regs *fiq_regs = regs; - - __fiq_ll_setup(fiq_regs->ARM_r8, fiq_regs->ARM_r9, fiq_regs->ARM_fp, - __get_cpu_var(fiq_stack_cpu) + THREAD_START_SP); -} - - /** * Initializes the HCD. This function allocates memory for and initializes the * static parts of the usb_hcd and dwc_otg_hcd structures. It also registers the @@ -403,11 +531,8 @@ int hcd_init( #elif defined(PCI_INTERFACE) dwc_otg_device_t *otg_dev = pci_get_drvdata(_dev); #endif + int retval = 0; - int irqno; - struct pt_regs regs; - unsigned long flags = IRQF_SHARED | IRQF_DISABLED; - int cpu; DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD INIT\n"); @@ -464,74 +589,6 @@ int hcd_init( goto error2; } - if (fiq_enable && dwc_otg_hcd->core_if->use_fiq_flag) - { - if (claim_fiq(&fh)) { - DWC_ERROR("Can't claim FIQ"); - goto error2; - } - - DWC_WARN("FIQ at 0x%08x", (fiq_fsm_enable ? (int)&dwc_otg_fiq_fsm : (int)&dwc_otg_fiq_nop)); - DWC_WARN("FIQ ASM at 0x%08x length %d", (int)&_dwc_otg_fiq_stub, (int)(&_dwc_otg_fiq_stub_end - &_dwc_otg_fiq_stub)); - - memset(®s,0,sizeof(regs)); - - regs.ARM_r8 = (long) dwc_otg_hcd->fiq_state; - if (fiq_fsm_enable) { - regs.ARM_r9 = dwc_otg_hcd->core_if->core_params->host_channels; - //regs.ARM_r10 = dwc_otg_hcd->dma; - regs.ARM_fp = (long) dwc_otg_fiq_fsm; - DWC_WARN("FIQ r8=0x%08x r9=0x%08x", (unsigned int)regs.ARM_r8,(unsigned int)regs.ARM_r9); - } else { - regs.ARM_fp = (long) dwc_otg_fiq_nop; - } - - mutex_lock(&fiq_lock); - - for_each_possible_cpu(cpu) { - void *stack; - stack = (void *) __get_free_pages(GFP_KERNEL, THREAD_SIZE_ORDER); - if (WARN_ON(!stack)) { - retval = -ENOMEM; - mutex_unlock(&fiq_lock); - goto error3; - } - per_cpu(fiq_stack_cpu, cpu) = stack; - } - - on_each_cpu(fiq_setup_helper, ®s, true); - set_fiq_handler((void *) &_dwc_otg_fiq_stub, &_dwc_otg_fiq_stub_end - &_dwc_otg_fiq_stub); - - mutex_unlock(&fiq_lock); - -// __show_regs(®s); - - //Set the mphi periph to the required registers - //dwc_otg_hcd->fiq_state->mphi_regs.base = otg_dev->os_dep.mphi_base; - //dwc_otg_hcd->fiq_state->mphi_regs.ctrl = otg_dev->os_dep.mphi_base + 0x4c; - //dwc_otg_hcd->fiq_state->mphi_regs.outdda = otg_dev->os_dep.mphi_base + 0x28; - //dwc_otg_hcd->fiq_state->mphi_regs.outddb = otg_dev->os_dep.mphi_base + 0x2c; - //dwc_otg_hcd->fiq_state->mphi_regs.intstat = otg_dev->os_dep.mphi_base + 0x50; - dwc_otg_hcd->fiq_state->dwc_regs_base = otg_dev->os_dep.base; - //DWC_WARN("MPHI regs_base at 0x%08x", (int)dwc_otg_hcd->fiq_state->mphi_regs.base); - //Enable mphi peripheral - //writel((1<<31),dwc_otg_hcd->fiq_state->mphi_regs.ctrl); -#ifdef DEBUG - //if (readl(dwc_otg_hcd->fiq_state->mphi_regs.ctrl) & 0x80000000) - // DWC_WARN("MPHI periph has been enabled"); - //else - // DWC_WARN("MPHI periph has NOT been enabled"); -#endif - //clear Timer D register - aml_clr_reg32_mask(P_ISA_TIMER_MUX, ((3<<6)|(1<<15)|(1<<19))); - aml_set_reg32_mask(P_ISA_TIMER_MUX, ((0<<6) | (0<<15) | (1<<19))); - printk("enable fiq %d\n",_dev->irq); - set_fiq_init(_dev->irq,(long)dwc_otg_hcd); - local_fiq_enable(); - - } - - otg_dev->hcd->otg_dev = otg_dev; hcd->self.otg_port = dwc_otg_hcd_otg_port(dwc_otg_hcd); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33) //don't support for LM(with 2.6.20.1 kernel) @@ -544,32 +601,19 @@ int hcd_init( // if (otg_dev->core_if->otg_ver) // hcd->self.is_hnp_cap = dwc_otg_get_hnpcapable(otg_dev->core_if); #endif - if (fiq_enable && dwc_otg_hcd->core_if->use_fiq_flag) { - irqno = MESON_USB_FIQ_BRIDGE; - } else { - irqno = _dev->irq; - flags |= IRQ_TYPE_LEVEL_HIGH; - } /* * Finish generic HCD initialization and start the HCD. This function * allocates the DMA buffer pool, registers the USB bus, requests the * IRQ line, and calls hcd_start method. */ - retval = usb_add_hcd(hcd, irqno, flags); + retval = usb_add_hcd(hcd, _dev->irq, IRQF_SHARED | IRQF_DISABLED); if (retval < 0) { - goto error3; + goto error2; } dwc_otg_hcd_set_priv_data(dwc_otg_hcd, hcd); return 0; -error3: - mutex_lock(&fiq_lock); - for_each_possible_cpu(cpu) { - __free_pages(per_cpu(fiq_stack_cpu, cpu), THREAD_SIZE_ORDER); - per_cpu(fiq_stack_cpu, cpu) = NULL; - } - mutex_unlock(&fiq_lock); error2: usb_put_hcd(hcd); error1: @@ -673,13 +717,11 @@ int hcd_suspend(struct usb_hcd *hcd) { dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd); dwc_otg_hcd->auto_pm_suspend_flag = (hcd->flags>>31)&1; - dwc_otg_hcd->pm_freeze_flag = (hcd->flags >> 30) & 1; DWC_DEBUGPL(DBG_HCD, "HCD SUSPEND\n"); dwc_otg_hcd_suspend(dwc_otg_hcd); hcd->flags &= (~(1<<31)); - hcd->flags &= (~(1<<30)); return 0; } @@ -689,26 +731,19 @@ int hcd_resume(struct usb_hcd *hcd) { dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd); dwc_otg_hcd->auto_pm_suspend_flag = (hcd->flags>>31)&1; - dwc_otg_hcd->pm_freeze_flag = (hcd->flags >> 30) & 1; - + DWC_DEBUGPL(DBG_HCD, "HCD RESUME\n"); dwc_otg_hcd_resume(dwc_otg_hcd); hcd->flags &= (~(1<<31)); - hcd->flags &= (~(1<<30)); - return 0; } /** Returns the current frame number. */ static int get_frame_number(struct usb_hcd *hcd) { - hprt0_data_t hprt0; dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd); - hprt0.d32 = DWC_READ_REG32(dwc_otg_hcd->core_if->host_if->hprt0); - if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED) - return dwc_otg_hcd_get_frame_number(dwc_otg_hcd) >> 3; - else + return dwc_otg_hcd_get_frame_number(dwc_otg_hcd); } @@ -836,15 +871,16 @@ static int urb_enqueue(struct usb_hcd *hcd, usb_maxpacket(urb->dev, urb->pipe, !(usb_pipein(urb->pipe)))); - if (hcd->self.uses_dma && (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP) && - !urb->transfer_buffer) - { - DWC_ERROR("dwc_otg_hcd: urb->transfer_buffer not set. Bailing out.\n"); - DWC_FREE(dwc_otg_urb); - return -EINVAL; - } - buf = urb->transfer_buffer; + if (hcd->self.uses_dma) { + /* + * Calculate virtual address from physical address, + * because some class driver may not fill transfer_buffer. + * In Buffer DMA mode virual address is used, + * when handling non DWORD aligned buffers. + */ + buf = phys_to_virt(urb->transfer_dma); + } if (!(urb->transfer_flags & URB_NO_INTERRUPT)) flags |= URB_GIVEBACK_ASAP; @@ -919,6 +955,10 @@ static int urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) if(unlikely(retval)) goto EXIT; #endif + if(usb_pipeint(urb->pipe) && (dwc_otg_hcd->ssplit_lock == usb_pipedevice(urb->pipe))){ + DWC_DEBUGPL(DBG_HCD, "addr=%d(%p)\n",usb_pipedevice(urb->pipe),urb->hcpriv); + dwc_otg_hcd->ssplit_lock = 0; + } if(urb->hcpriv == NULL){ DWC_WARN("urb->hcpriv == NULL! urb = %p status=%d\n",urb,status); @@ -961,6 +1001,8 @@ static void endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep) "endpoint=%d,is_intr=%d\n", ep->desc.bEndpointAddress, dwc_ep_addr_to_endpoint(ep->desc.bEndpointAddress), usb_endpoint_xfer_int(&ep->desc)); + if(usb_endpoint_xfer_int(&ep->desc)) + dwc_otg_hcd->ssplit_lock = 0; dwc_otg_hcd_endpoint_disable(dwc_otg_hcd, ep->hcpriv, 250); ep->hcpriv = NULL; } @@ -974,6 +1016,9 @@ static void endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep) dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd); DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags); + + if(usb_endpoint_xfer_int(&ep->desc)) + dwc_otg_hcd->ssplit_lock = 0; if (ep->hcpriv) { dwc_otg_hcd_endpoint_reset(dwc_otg_hcd, ep->hcpriv); diff --git a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_hcd_queue.c b/drivers/amlogic/usb/dwc_otg/310/dwc_otg_hcd_queue.c old mode 100755 new mode 100644 index 41ff30f4b219..e1a0f305561e --- a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_hcd_queue.c +++ b/drivers/amlogic/usb/dwc_otg/310/dwc_otg_hcd_queue.c @@ -42,8 +42,6 @@ #include "dwc_otg_hcd.h" #include "dwc_otg_regs.h" -extern bool microframe_schedule; - /** * Free each QTD in the QH's QTD-list then free the QH. QH should already be * removed from a list. QTD list should already be empty if called from URB @@ -155,6 +153,7 @@ static uint32_t calc_bus_time(int speed, int is_in, int is_isoc, int bytecount) * to initialize the QH. */ #define SCHEDULE_SLOP 10 +#define SCHEDULE_SPLIT_SLOP 10 void qh_init(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, dwc_otg_hcd_urb_t * urb) { char *speed, *type; @@ -179,10 +178,6 @@ void qh_init(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, dwc_otg_hcd_urb_t * urb) hcd->fops->hub_info(hcd, urb->priv, &hub_addr, &hub_port); qh->do_split = 0; - if (microframe_schedule) - qh->speed = dev_speed; - - qh->nak_frame = 0xffff; if (((dev_speed == USB_SPEED_LOW) || (dev_speed == USB_SPEED_FULL)) && @@ -192,7 +187,6 @@ 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) { @@ -227,6 +221,10 @@ void qh_init(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, dwc_otg_hcd_urb_t * urb) qh->start_split_frame = qh->sched_frame; } + }else if(qh->do_split){ + qh->interval = SCHEDULE_SPLIT_SLOP; + qh->sched_frame = dwc_frame_num_inc(hcd->frame_number, + SCHEDULE_SPLIT_SLOP); } DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD QH Initialized\n"); @@ -319,8 +317,6 @@ dwc_otg_qh_t *dwc_otg_hcd_qh_create(dwc_otg_hcd_t * hcd, return qh; } -/* microframe_schedule=0 start */ - /** * Checks that a channel is available for a periodic transfer. * @@ -389,162 +385,6 @@ static int check_periodic_bandwidth(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) return status; } -/* microframe_schedule=0 end */ - -/** - * Microframe scheduler - * track the total use in hcd->frame_usecs - * keep each qh use in qh->frame_usecs - * when surrendering the qh then donate the time back - */ -const unsigned short max_uframe_usecs[]={ 100, 100, 100, 100, 100, 100, 30, 0 }; - -/* - * called from dwc_otg_hcd.c:dwc_otg_hcd_init - */ -int init_hcd_usecs(dwc_otg_hcd_t *_hcd) -{ - int i; - for (i=0; i<8; i++) { - _hcd->frame_usecs[i] = max_uframe_usecs[i]; - } - return 0; -} - -static int find_single_uframe(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh) -{ - int i; - unsigned short utime; - int t_left; - int ret; - int done; - - ret = -1; - utime = _qh->usecs; - t_left = utime; - i = 0; - done = 0; - while (done == 0) { - /* At the start _hcd->frame_usecs[i] = max_uframe_usecs[i]; */ - if (utime <= _hcd->frame_usecs[i]) { - _hcd->frame_usecs[i] -= utime; - _qh->frame_usecs[i] += utime; - t_left -= utime; - ret = i; - done = 1; - return ret; - } else { - i++; - if (i == 8) { - done = 1; - ret = -1; - } - } - } - return ret; - } - -/* - * use this for FS apps that can span multiple uframes - */ -static int find_multi_uframe(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh) -{ - int i; - int j; - unsigned short utime; - int t_left; - int ret; - int done; - unsigned short xtime; - - ret = -1; - utime = _qh->usecs; - t_left = utime; - i = 0; - done = 0; -loop: - while (done == 0) { - if(_hcd->frame_usecs[i] <= 0) { - i++; - if (i == 8) { - done = 1; - ret = -1; - } - goto loop; - } - - /* - * we need n consecutive slots - * so use j as a start slot j plus j+1 must be enough time (for now) - */ - xtime= _hcd->frame_usecs[i]; - for (j = i+1 ; j < 8 ; j++ ) { - /* - * if we add this frame remaining time to xtime we may - * be OK, if not we need to test j for a complete frame - */ - if ((xtime+_hcd->frame_usecs[j]) < utime) { - if (_hcd->frame_usecs[j] < max_uframe_usecs[j]) { - j = 8; - ret = -1; - continue; - } - } - if (xtime >= utime) { - ret = i; - j = 8; /* stop loop with a good value ret */ - continue; - } - /* add the frame time to x time */ - xtime += _hcd->frame_usecs[j]; - /* we must have a fully available next frame or break */ - if ((xtime < utime) - && (_hcd->frame_usecs[j] == max_uframe_usecs[j])) { - ret = -1; - j = 8; /* stop loop with a bad value ret */ - continue; - } - } - if (ret >= 0) { - t_left = utime; - for (j = i; (t_left>0) && (j < 8); j++ ) { - t_left -= _hcd->frame_usecs[j]; - if ( t_left <= 0 ) { - _qh->frame_usecs[j] += _hcd->frame_usecs[j] + t_left; - _hcd->frame_usecs[j]= -t_left; - ret = i; - done = 1; - } else { - _qh->frame_usecs[j] += _hcd->frame_usecs[j]; - _hcd->frame_usecs[j] = 0; - } - } - } else { - i++; - if (i == 8) { - done = 1; - ret = -1; - } - } - } - return ret; -} - -static int find_uframe(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh) -{ - int ret; - ret = -1; - - if (_qh->speed == USB_SPEED_HIGH) { - /* if this is a hs transaction we need a full frame */ - ret = find_single_uframe(_hcd, _qh); - } else { - /* if this is a fs transaction we may need a sequence of frames */ - ret = find_multi_uframe(_hcd, _qh); - } - return ret; -} - /** * Checks that the max transfer size allowed in a host channel is large enough * to handle the maximum data transfer in a single (micro)frame for a periodic @@ -575,8 +415,6 @@ static int check_max_xfer_size(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) return status; } - - /** * Schedules an interrupt or isochronous transfer in the periodic schedule. * @@ -589,27 +427,8 @@ static int check_max_xfer_size(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) static int schedule_periodic(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) { int status = 0; + uint16_t frame_number; - if (microframe_schedule) { - int frame; - status = find_uframe(hcd, qh); - frame = -1; - if (status == 0) { - frame = 7; - } else { - if (status > 0 ) - frame = status-1; - } - - /* Set the new frame up */ - if (frame > -1) { - qh->sched_frame &= ~0x7; - qh->sched_frame |= (frame & 7); - } - - if (status != -1) - status = 0; - } else { status = periodic_channel_available(hcd); if (status) { DWC_INFO("%s: No host channel available for periodic " "transfer.\n", __func__); //NOTICE @@ -617,35 +436,39 @@ static int schedule_periodic(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) } status = check_periodic_bandwidth(hcd, qh); - } if (status) { DWC_INFO("%s: Insufficient periodic bandwidth for " "periodic transfer.\n", __func__); //NOTICE return status; } + status = check_max_xfer_size(hcd, qh); if (status) { DWC_INFO("%s: Channel max transfer size too small " "for periodic transfer.\n", __func__); //NOTICE return status; } + + frame_number = dwc_otg_hcd_get_frame_number(hcd); + if((qh->ep_type == UE_INTERRUPT) && !(qh->ep_is_in)){ + //if(((frame_sched - frame_number) > _qh->interval) || dwc_frame_num_le(frame_number,DWC_HFNUM_MAX_FRNUM + frame_sched)){ + qh->sched_frame = dwc_frame_num_inc(frame_number, SCHEDULE_SLOP); + //}//fix it in future + } + + if((qh->ep_type == UE_INTERRUPT) && !qh->do_split && + !dwc_frame_num_le(qh->sched_frame,dwc_frame_num_inc(frame_number,qh->interval))) + qh->sched_frame = dwc_frame_num_inc(frame_number, qh->interval); if (hcd->core_if->dma_desc_enable) { /* Don't rely on SOF and start in ready schedule */ DWC_LIST_INSERT_TAIL(&hcd->periodic_sched_ready, &qh->qh_list_entry); } else { - if(fiq_enable &&hcd->core_if->use_fiq_flag && (DWC_LIST_EMPTY(&hcd->periodic_sched_inactive) || dwc_frame_num_le(qh->sched_frame, hcd->fiq_state->next_sched_frame))) - { - hcd->fiq_state->next_sched_frame = qh->sched_frame; - - } /* Always start in the inactive schedule. */ DWC_LIST_INSERT_TAIL(&hcd->periodic_sched_inactive, &qh->qh_list_entry); } - if (!microframe_schedule) { /* Reserve the periodic channel. */ hcd->periodic_channels++; - } /* Update claimed usecs per (micro)frame. */ hcd->periodic_usecs += qh->usecs; @@ -653,7 +476,6 @@ static int schedule_periodic(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) return status; } - /** * This function adds a QH to either the non periodic or periodic schedule if * it is not already in the schedule. If the QH is already in the schedule, no @@ -697,21 +519,13 @@ int dwc_otg_hcd_qh_add(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) */ static void deschedule_periodic(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) { - int i; DWC_LIST_REMOVE_INIT(&qh->qh_list_entry); + /* Release the periodic channel reservation. */ + hcd->periodic_channels--; + /* Update claimed usecs per (micro)frame. */ hcd->periodic_usecs -= qh->usecs; - - if (!microframe_schedule) { - /* Release the periodic channel reservation. */ - hcd->periodic_channels--; - } else { - for (i = 0; i < 8; i++) { - hcd->frame_usecs[i] += qh->frame_usecs[i]; - qh->frame_usecs[i] = 0; - } - } } /** @@ -738,7 +552,7 @@ void dwc_otg_hcd_qh_remove(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) } else { deschedule_periodic(hcd, qh); hcd->periodic_qh_count--; - if( !hcd->periodic_qh_count && !(fiq_fsm_enable &&hcd->core_if->use_fiq_flag)) { + if( !hcd->periodic_qh_count ) { intr_mask.b.sofintr = 1; DWC_MODIFY_REG32(&hcd->core_if->core_global_regs->gintmsk, intr_mask.d32, 0); @@ -818,16 +632,10 @@ void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, * Remove from periodic_sched_queued and move to * appropriate queue. */ - if ((microframe_schedule && dwc_frame_num_le(qh->sched_frame, frame_number)) || - (!microframe_schedule && qh->sched_frame == frame_number)) { + if (qh->sched_frame == frame_number) { DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_ready, &qh->qh_list_entry); } else { - if(fiq_enable && hcd->core_if->use_fiq_flag && !dwc_frame_num_le(hcd->fiq_state->next_sched_frame, qh->sched_frame)) - { - hcd->fiq_state->next_sched_frame = qh->sched_frame; - } - DWC_LIST_MOVE_HEAD (&hcd->periodic_sched_inactive, &qh->qh_list_entry); @@ -884,6 +692,7 @@ void dwc_otg_hcd_qtd_init(dwc_otg_qtd_t * qtd, dwc_otg_hcd_urb_t * urb) /* Store the qtd ptr in the urb to reference what QTD. */ urb->qtd = qtd; + urb->qh_state = URB_STATE_IDLE; return; } @@ -917,9 +726,6 @@ int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * qtd, if (*qh == NULL) { retval = -1; goto done; - } else { - if (fiq_enable && hcd->core_if->use_fiq_flag) - hcd->fiq_state->kick_np_queues = 1; } } // DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags); diff --git a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_pcd.c b/drivers/amlogic/usb/dwc_otg/310/dwc_otg_pcd.c old mode 100755 new mode 100644 diff --git a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_pcd.h b/drivers/amlogic/usb/dwc_otg/310/dwc_otg_pcd.h old mode 100755 new mode 100644 diff --git a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_pcd_if.h b/drivers/amlogic/usb/dwc_otg/310/dwc_otg_pcd_if.h old mode 100755 new mode 100644 diff --git a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_pcd_intr.c b/drivers/amlogic/usb/dwc_otg/310/dwc_otg_pcd_intr.c old mode 100755 new mode 100644 diff --git a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_pcd_linux.c b/drivers/amlogic/usb/dwc_otg/310/dwc_otg_pcd_linux.c index d40bfb06372b..d34fe8f9d655 100644 --- a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_pcd_linux.c +++ b/drivers/amlogic/usb/dwc_otg/310/dwc_otg_pcd_linux.c @@ -1282,7 +1282,7 @@ int pcd_init( */ DWC_DEBUGPL(DBG_ANY, "registering handler for irq%d\n", _dev->irq); retval = request_irq(_dev->irq, dwc_otg_pcd_irq, - IRQF_SHARED | IRQF_DISABLED | IRQ_TYPE_LEVEL_HIGH, + IRQF_SHARED | IRQF_DISABLED, gadget_wrapper->gadget.name, otg_dev->pcd); if (retval != 0) { DWC_ERROR("request of irq%d failed\n", _dev->irq); @@ -1290,6 +1290,11 @@ int pcd_init( return -EBUSY; } + if (irq_set_affinity(_dev->irq, cpumask_of(3))) { + pr_warning("unable to set irq affinity (irq=%d, cpu=%u)\n", + _dev->irq, 3); + } + dwc_otg_pcd_start(gadget_wrapper->pcd, &fops); return retval; diff --git a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_regs.h b/drivers/amlogic/usb/dwc_otg/310/dwc_otg_regs.h old mode 100755 new mode 100644 diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index db4633772335..e542f1724012 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -47,9 +47,6 @@ #include #include -#ifdef CONFIG_MESON_GIC_FIQ -#include -#endif #include "irqchip.h" union gic_base { @@ -83,9 +80,6 @@ static DEFINE_RAW_SPINLOCK(irq_controller_lock); */ #define NR_GIC_CPU_IF 8 static u8 gic_cpu_map[NR_GIC_CPU_IF] __read_mostly; -#ifdef CONFIG_MESON_GIC_FIQ -static int gic_fiq_enable __read_mostly; -#endif /* * Supported arch specific GIC irq extension. @@ -105,9 +99,6 @@ struct irq_chip gic_arch_extn = { #endif static struct gic_chip_data gic_data[MAX_GIC_NR] __read_mostly; -#ifdef CONFIG_MESON_GIC_FIQ -static int gic_fiq_enable __read_mostly; -#endif #ifdef CONFIG_GIC_NON_BANKED static void __iomem *gic_get_percpu_base(union gic_base *base) @@ -303,7 +294,7 @@ static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs do { irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK); irqnr = irqstat & ~0x1c00; - + if (likely(irqnr > 15 && irqnr < 1021)) { irqnr = irq_find_mapping(gic->domain, irqnr); handle_IRQ(irqnr, regs); @@ -430,21 +421,7 @@ static void __init gic_dist_init(struct gic_chip_data *gic) for (i = 32; i < gic_irqs; i += 32) writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32); -#ifdef CONFIG_MESON_GIC_FIQ - if(gic_fiq_enable == 1) - writel_relaxed(3, base + GIC_DIST_CTRL); - else - writel_relaxed(1, base + GIC_DIST_CTRL); -#else - writel_relaxed(1, base + GIC_DIST_CTRL); -#endif -} - -void gic_set_fiq_fake(unsigned fiq,irq_flow_handler_t handle) -{ - if((fiq>=32) && (fiq<=1020)){ - irq_set_chip_and_handler(fiq, &gic_chip, handle); - } + writel_relaxed(1, base + GIC_DIST_CTRL); } static void __cpuinit gic_cpu_init(struct gic_chip_data *gic) @@ -453,20 +430,7 @@ static void __cpuinit gic_cpu_init(struct gic_chip_data *gic) void __iomem *base = gic_data_cpu_base(gic); unsigned int cpu_mask, cpu = smp_processor_id(); int i; -#ifdef CONFIG_MESON_GIC_FIQ -/********************************************* -* suspend/resume need save&restore GIC FIQ setting -*********************************************/ - unsigned int it_lines_number; - unsigned cmd; - char c=0; - unsigned temp; - if(gic_fiq_enable == 1){ - cmd = readl_relaxed((const volatile void *)P_AO_RTI_STATUS_REG1); - c = (char)cmd; - } -#endif /* * Get what the GIC says our CPU mask is. */ @@ -489,51 +453,14 @@ static void __cpuinit gic_cpu_init(struct gic_chip_data *gic) writel_relaxed(0xffff0000, dist_base + GIC_DIST_ENABLE_CLEAR); writel_relaxed(0x0000ffff, dist_base + GIC_DIST_ENABLE_SET); -#ifdef CONFIG_MESON_GIC_FIQ - if(gic_fiq_enable == 1){ - /* Set the Per-CPU interrupts 15-8 as Secure and the rest - * as Non-secure */ - it_lines_number = readl_relaxed(dist_base + GIC_DIST_CTR) & 0x1f; - writel_relaxed(0xffff00ff, dist_base + GIC_DIST_IGROUP); - - if(c != 'r'){ - /* Set ALL interrupts as non-secure interrupts */ - for(i = 1; i <= it_lines_number; i++) { - temp = readl_relaxed(dist_base + GIC_DIST_IGROUP + i * 4); - if(temp == 0) - writel_relaxed(0xffffffff, dist_base + GIC_DIST_IGROUP + i * 4); - } - } - /* - * Set priority on PPI and SGI interrupts - */ - for (i = 0; i < 32; i += 4){ - temp = readl_relaxed(dist_base + GIC_DIST_PRI + i * 4 / 4); - if(temp == 0) - writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4 / 4); - } - } - else{ - for (i = 0; i < 32; i += 4) - writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4 / 4); - } -#else /* * Set priority on PPI and SGI interrupts */ for (i = 0; i < 32; i += 4) writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4 / 4); -#endif writel_relaxed(0xf0, base + GIC_CPU_PRIMASK); -#ifdef CONFIG_MESON_GIC_FIQ - if(gic_fiq_enable == 1) - writel_relaxed(0xf, base + GIC_CPU_CTRL); //??GICC_ACTR maybe set 0 - else - writel_relaxed(1, base + GIC_CPU_CTRL); -#else writel_relaxed(1, base + GIC_CPU_CTRL); -#endif } #ifdef CONFIG_CPU_PM @@ -611,14 +538,7 @@ static void gic_dist_restore(unsigned int gic_nr) writel_relaxed(gic_data[gic_nr].saved_spi_enable[i], dist_base + GIC_DIST_ENABLE_SET + i * 4); -#ifdef CONFIG_MESON_GIC_FIQ - if(gic_fiq_enable == 1) - writel_relaxed(3, dist_base + GIC_DIST_CTRL); - else - writel_relaxed(1, dist_base + GIC_DIST_CTRL); -#else writel_relaxed(1, dist_base + GIC_DIST_CTRL); -#endif } static void gic_cpu_save(unsigned int gic_nr) @@ -675,14 +595,7 @@ static void gic_cpu_restore(unsigned int gic_nr) writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4); writel_relaxed(0xf0, cpu_base + GIC_CPU_PRIMASK); -#ifdef CONFIG_MESON_GIC_FIQ - if(gic_fiq_enable == 1) - writel_relaxed(0xf, cpu_base + GIC_CPU_CTRL); - else - writel_relaxed(1, cpu_base + GIC_CPU_CTRL); -#else writel_relaxed(1, cpu_base + GIC_CPU_CTRL); -#endif } static int gic_notifier(struct notifier_block *self, unsigned long cmd, void *v) @@ -756,14 +669,7 @@ void gic_raise_softirq(const struct cpumask *mask, unsigned int irq) dsb(); /* this always happens on GIC0 */ -#ifdef CONFIG_MESON_GIC_FIQ - if(gic_fiq_enable == 1) - writel_relaxed(map << 16 | 1<<15 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT); - else - writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT); -#else writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT); -#endif } #endif @@ -948,13 +854,6 @@ int __init gic_of_init(struct device_node *node, struct device_node *parent) if (of_property_read_u32(node, "cpu-offset", &percpu_offset)) percpu_offset = 0; - -#ifdef CONFIG_MESON_GIC_FIQ - if(of_property_read_bool(node, "gic_fiq_enable")) - gic_fiq_enable=1; - else - gic_fiq_enable = 0; -#endif gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset, node); @@ -971,11 +870,4 @@ IRQCHIP_DECLARE(cortex_a7_gic, "arm,cortex-a7-gic", gic_of_init); IRQCHIP_DECLARE(msm_8660_qgic, "qcom,msm-8660-qgic", gic_of_init); IRQCHIP_DECLARE(msm_qgic2, "qcom,msm-qgic2", gic_of_init); -#ifdef CONFIG_MESON_GIC_FIQ -int get_gic_fiq_enable_flag(void) -{ - return gic_fiq_enable; -} -#endif - #endif diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c old mode 100755 new mode 100644 index 7ca5c5e910d1..cbd97ce0b000 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -15,7 +15,7 @@ #include #include #include -#include + #include #include "internals.h" @@ -454,7 +454,7 @@ handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc) goto out; } - if ((irq!=get_fiq_index()) && (desc->istate & IRQS_ONESHOT)) + if (desc->istate & IRQS_ONESHOT) mask_irq(desc); preflow_handler(desc);