diff --git a/target/linux/gemini/Makefile b/target/linux/gemini/Makefile index b7f1962c9a5..b2869ff72ed 100644 --- a/target/linux/gemini/Makefile +++ b/target/linux/gemini/Makefile @@ -11,7 +11,7 @@ FEATURES:=squashfs pci rtc usb dt gpio display ext4 rootfs-part boot-part CPU_TYPE:=fa526 SUBTARGETS:=generic -KERNEL_PATCHVER:=6.1 +KERNEL_PATCHVER:=6.6 define Target/Description Build firmware images for the StorLink/Cortina Gemini CS351x ARM FA526 CPU diff --git a/target/linux/gemini/config-6.1 b/target/linux/gemini/config-6.6 similarity index 92% rename from target/linux/gemini/config-6.1 rename to target/linux/gemini/config-6.6 index ae0922f5dc8..d670279135f 100644 --- a/target/linux/gemini/config-6.1 +++ b/target/linux/gemini/config-6.6 @@ -10,10 +10,10 @@ CONFIG_ARCH_MULTI_V4=y # CONFIG_ARCH_MULTI_V4T is not set CONFIG_ARCH_MULTI_V4_V5=y # CONFIG_ARCH_MULTI_V5 is not set -CONFIG_ARCH_NR_GPIO=0 CONFIG_ARCH_OPTIONAL_KERNEL_RWX=y CONFIG_ARCH_SELECT_MEMORY_MODEL=y CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_STACKWALK=y CONFIG_ARM=y CONFIG_ARM_AMBA=y CONFIG_ARM_APPENDED_DTB=y @@ -21,7 +21,6 @@ CONFIG_ARM_APPENDED_DTB=y CONFIG_ARM_HAS_GROUP_RELOCS=y CONFIG_ARM_L1_CACHE_SHIFT=5 CONFIG_ARM_PATCH_PHYS_VIRT=y -# CONFIG_ARM_SMMU is not set CONFIG_ARM_UNWIND=y CONFIG_ATA=y CONFIG_ATAGS=y @@ -33,6 +32,8 @@ CONFIG_BLK_DEV_SD=y CONFIG_BLK_MQ_PCI=y CONFIG_BLK_PM=y CONFIG_BOUNCE=y +CONFIG_BUFFER_HEAD=y +CONFIG_CACHESTAT_SYSCALL=y CONFIG_CC_HAVE_STACKPROTECTOR_TLS=y CONFIG_CC_IMPLICIT_FALLTHROUGH="-Wimplicit-fallthrough=5" CONFIG_CC_NO_ARRAY_BOUNDS=y @@ -84,6 +85,7 @@ CONFIG_CROSS_MEMORY_ATTACH=y CONFIG_CRYPTO_CMAC=y CONFIG_CRYPTO_CRC32C=y CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_DEV_JH7110 is not set CONFIG_CRYPTO_DEV_SL3516=y # CONFIG_CRYPTO_DEV_SL3516_DEBUG is not set CONFIG_CRYPTO_DRBG=y @@ -92,14 +94,18 @@ CONFIG_CRYPTO_DRBG_MENU=y CONFIG_CRYPTO_ECB=y CONFIG_CRYPTO_ECHAINIV=y CONFIG_CRYPTO_ENGINE=y +CONFIG_CRYPTO_GENIV=y CONFIG_CRYPTO_HMAC=y CONFIG_CRYPTO_HW=y CONFIG_CRYPTO_JITTERENTROPY=y CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y CONFIG_CRYPTO_LIB_DES=y +CONFIG_CRYPTO_LIB_GF128MUL=y CONFIG_CRYPTO_LIB_SHA1=y CONFIG_CRYPTO_LIB_SHA256=y CONFIG_CRYPTO_LIB_UTILS=y +# CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set +# CONFIG_CRYPTO_MANAGER_EXTRA_TESTS is not set CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_MD5=y CONFIG_CRYPTO_RNG=y @@ -107,7 +113,10 @@ CONFIG_CRYPTO_RNG2=y CONFIG_CRYPTO_RNG_DEFAULT=y CONFIG_CRYPTO_SEQIV=y CONFIG_CRYPTO_SHA256=y +CONFIG_CRYPTO_SHA3=y CONFIG_CRYPTO_SHA512=y +CONFIG_CRYPTO_SIG2=y +CONFIG_CRYPTO_USER=y CONFIG_DEBUG_BUGVERBOSE=y CONFIG_DEBUG_INFO=y CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S" @@ -133,7 +142,6 @@ CONFIG_DRM_FBDEV_EMULATION=y CONFIG_DRM_FBDEV_OVERALLOC=100 CONFIG_DRM_GEM_DMA_HELPER=y CONFIG_DRM_KMS_HELPER=y -CONFIG_DRM_NOMODESET=y CONFIG_DRM_PANEL=y CONFIG_DRM_PANEL_BRIDGE=y CONFIG_DRM_PANEL_ILITEK_IL9322=y @@ -145,18 +153,17 @@ CONFIG_EDAC_ATOMIC_SCRUB=y CONFIG_EDAC_SUPPORT=y CONFIG_EEPROM_93CX6=y CONFIG_ELF_CORE=y -# CONFIG_EMBEDDED is not set CONFIG_EXCLUSIVE_SYSTEM_RAM=y # CONFIG_EXPERT is not set CONFIG_EXT4_FS=y CONFIG_EXTCON=y CONFIG_FARADAY_FTINTC010=y CONFIG_FB=y -CONFIG_FB_CFB_COPYAREA=y -CONFIG_FB_CFB_FILLRECT=y -CONFIG_FB_CFB_IMAGEBLIT=y -CONFIG_FB_CMDLINE=y +CONFIG_FB_CORE=y CONFIG_FB_DEFERRED_IO=y +CONFIG_FB_DMAMEM_HELPERS=y +CONFIG_FB_SYSMEM_HELPERS=y +CONFIG_FB_SYSMEM_HELPERS_DEFERRED=y CONFIG_FB_SYS_COPYAREA=y CONFIG_FB_SYS_FILLRECT=y CONFIG_FB_SYS_FOPS=y @@ -175,11 +182,13 @@ CONFIG_FS_MBCACHE=y CONFIG_FS_POSIX_ACL=y CONFIG_FTTMR010_TIMER=y CONFIG_FTWDT010_WATCHDOG=y +CONFIG_FUNCTION_ALIGNMENT=0 CONFIG_FWNODE_MDIO=y CONFIG_FW_LOADER_PAGED_BUF=y CONFIG_FW_LOADER_SYSFS=y # CONFIG_FW_LOADER_USER_HELPER_FALLBACK is not set -CONFIG_GCC11_NO_ARRAY_BOUNDS=y +CONFIG_GCC10_NO_ARRAY_BOUNDS=y +CONFIG_GCC_ASM_GOTO_OUTPUT_WORKAROUND=y CONFIG_GEMINI_ETHERNET=y CONFIG_GENERIC_ALLOCATOR=y CONFIG_GENERIC_ATOMIC64=y @@ -207,6 +216,7 @@ CONFIG_GRO_CELLS=y CONFIG_HARDIRQS_SW_RESEND=y CONFIG_HAS_DMA=y CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y CONFIG_HAS_IOPORT_MAP=y CONFIG_HDMI=y CONFIG_HIGHMEM=y @@ -224,10 +234,6 @@ CONFIG_I2C_HELPER_AUTO=y CONFIG_INITRAMFS_SOURCE="" CONFIG_INPUT=y CONFIG_INPUT_KEYBOARD=y -# CONFIG_IOMMU_DEBUGFS is not set -# CONFIG_IOMMU_IO_PGTABLE_ARMV7S is not set -# CONFIG_IOMMU_IO_PGTABLE_LPAE is not set -CONFIG_IOMMU_SUPPORT=y CONFIG_IO_URING=y CONFIG_IPC_NS=y CONFIG_IRQCHIP=y @@ -263,10 +269,10 @@ CONFIG_MDIO_BUS=y CONFIG_MDIO_DEVICE=y CONFIG_MDIO_DEVRES=y CONFIG_MDIO_GPIO=y -CONFIG_MEMFD_CREATE=y CONFIG_MEMORY_ISOLATION=y CONFIG_MFD_SYSCON=y CONFIG_MIGRATION=y +CONFIG_MMU_LAZY_TLB_REFCOUNT=y CONFIG_MODULES_USE_ELF_REL=y # CONFIG_MODULE_UNLOAD is not set CONFIG_MQ_IOSCHED_DEADLINE=y @@ -282,6 +288,7 @@ CONFIG_NAMESPACES=y CONFIG_NEED_DMA_MAP_STATE=y CONFIG_NEED_KUSER_HELPERS=y CONFIG_NEED_PER_CPU_KM=y +CONFIG_NEED_SRCU_NMI_SAFE=y CONFIG_NET_DEVLINK=y CONFIG_NET_DSA=y CONFIG_NET_DSA_REALTEK=y @@ -290,13 +297,17 @@ CONFIG_NET_DSA_REALTEK=y CONFIG_NET_DSA_REALTEK_RTL8366RB=y CONFIG_NET_DSA_REALTEK_SMI=y CONFIG_NET_DSA_TAG_RTL4_A=y +CONFIG_NET_EGRESS=y +CONFIG_NET_INGRESS=y CONFIG_NET_NS=y CONFIG_NET_SELFTESTS=y CONFIG_NET_SWITCHDEV=y +CONFIG_NET_XGRESS=y CONFIG_NLS=y CONFIG_NO_HZ_COMMON=y CONFIG_NO_HZ_IDLE=y CONFIG_NVMEM=y +CONFIG_NVMEM_LAYOUTS=y CONFIG_OF=y CONFIG_OF_ADDRESS=y CONFIG_OF_EARLY_FLATTREE=y @@ -311,6 +322,7 @@ CONFIG_PAGE_OFFSET=0xC0000000 CONFIG_PAGE_POOL=y CONFIG_PAGE_SIZE_LESS_THAN_256KB=y CONFIG_PAGE_SIZE_LESS_THAN_64KB=y +CONFIG_PAHOLE_HAS_LANG_EXCLUDE=y # CONFIG_PANIC_ON_OOPS is not set CONFIG_PANIC_ON_OOPS_VALUE=0 CONFIG_PANIC_TIMEOUT=0 @@ -327,6 +339,7 @@ CONFIG_PCI_FTPCI100=y CONFIG_PERF_USE_VMALLOC=y CONFIG_PGTABLE_LEVELS=2 CONFIG_PHYLIB=y +CONFIG_PHYLIB_LEDS=y CONFIG_PHYLINK=y CONFIG_PID_NS=y CONFIG_PINCTRL=y @@ -382,12 +395,14 @@ CONFIG_SERIAL_8250_EXAR=y CONFIG_SERIAL_8250_FSL=y CONFIG_SERIAL_8250_NR_UARTS=1 CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_8250_PCILIB=y CONFIG_SERIAL_8250_RUNTIME_UARTS=1 CONFIG_SERIAL_MCTRL_GPIO=y CONFIG_SERIAL_OF_PLATFORM=y CONFIG_SERIO=y CONFIG_SERIO_LIBPS2=y CONFIG_SERIO_SERPORT=y +CONFIG_SGL_ALLOC=y CONFIG_SG_POOL=y CONFIG_SLUB_DEBUG=y CONFIG_SOFTIRQ_ON_OWN_STACK=y @@ -397,7 +412,7 @@ CONFIG_SPI_BITBANG=y CONFIG_SPI_GPIO=y CONFIG_SPI_MASTER=y CONFIG_SPLIT_PTLOCK_CPUS=999999 -CONFIG_SRCU=y +CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU=y CONFIG_STACKDEPOT=y CONFIG_STACKTRACE=y # CONFIG_STRIP_ASM_SYMS is not set @@ -432,6 +447,8 @@ CONFIG_USE_OF=y CONFIG_UTS_NS=y CONFIG_VGA_ARB=y CONFIG_VGA_ARB_MAX_GPUS=16 +CONFIG_VIDEO_CMDLINE=y +CONFIG_VIDEO_NOMODESET=y CONFIG_VITESSE_PHY=y CONFIG_VM_EVENT_COUNTERS=y CONFIG_VT=y diff --git a/target/linux/gemini/image/Makefile b/target/linux/gemini/image/Makefile index 3fce3172ed6..3ddb6e5554a 100644 --- a/target/linux/gemini/image/Makefile +++ b/target/linux/gemini/image/Makefile @@ -124,6 +124,7 @@ endef # All DTB files are prefixed with "gemini-" define Device/Default PROFILES := Default + DEVICE_DTS_DIR = $$(DTS_DIR)/gemini KERNEL_DEPENDS = $$(wildcard $(DTS_DIR)/$$(DEVICE_DTS).dts) KERNEL_NAME := zImage KERNEL := kernel-bin | append-dtb diff --git a/target/linux/gemini/patches-6.1/0001-usb-phy-phy-gpio-vbus-usb-Add-device-tree-probing.patch b/target/linux/gemini/patches-6.1/0001-usb-phy-phy-gpio-vbus-usb-Add-device-tree-probing.patch deleted file mode 100644 index 943b166d7e3..00000000000 --- a/target/linux/gemini/patches-6.1/0001-usb-phy-phy-gpio-vbus-usb-Add-device-tree-probing.patch +++ /dev/null @@ -1,67 +0,0 @@ -From d5a026cc8306ccd3e99e1455c87e38f8e6fa18df Mon Sep 17 00:00:00 2001 -From: Linus Walleij -Date: Mon, 7 Nov 2022 00:05:06 +0100 -Subject: [PATCH 01/29] usb: phy: phy-gpio-vbus-usb: Add device tree probing - -Make it possible to probe the GPIO VBUS detection driver -from the device tree compatible for GPIO USB B connectors. - -Since this driver is using the "gpio-usb-b-connector" -compatible, it is important to discern it from the role -switch connector driver (which does not provide a phy), -so we add some Kconfig text and depend on !USB_CONN_GPIO. - -Cc: Rob Herring -Cc: Prashant Malani -Cc: Felipe Balbi -Signed-off-by: Linus Walleij -Link: https://lore.kernel.org/r/20221106230506.1646101-1-linus.walleij@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- ---- a/drivers/usb/phy/Kconfig -+++ b/drivers/usb/phy/Kconfig -@@ -93,12 +93,16 @@ config USB_GPIO_VBUS - tristate "GPIO based peripheral-only VBUS sensing 'transceiver'" - depends on GPIOLIB || COMPILE_TEST - depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y' -+ depends on !USB_CONN_GPIO - select USB_PHY - help - Provides simple GPIO VBUS sensing for controllers with an - internal transceiver via the usb_phy interface, and - optionally control of a D+ pullup GPIO as well as a VBUS -- current limit regulator. -+ current limit regulator. This driver is for devices that do -+ NOT support role switch. OTG devices that can do role switch -+ (master/peripheral) shall use the USB based connection -+ detection driver USB_CONN_GPIO. - - config OMAP_OTG - tristate "OMAP USB OTG controller driver" ---- a/drivers/usb/phy/phy-gpio-vbus-usb.c -+++ b/drivers/usb/phy/phy-gpio-vbus-usb.c -@@ -366,12 +366,24 @@ static const struct dev_pm_ops gpio_vbus - - MODULE_ALIAS("platform:gpio-vbus"); - -+/* -+ * NOTE: this driver matches against "gpio-usb-b-connector" for -+ * devices that do NOT support role switch. -+ */ -+static const struct of_device_id gpio_vbus_of_match[] = { -+ { -+ .compatible = "gpio-usb-b-connector", -+ }, -+ {}, -+}; -+ - static struct platform_driver gpio_vbus_driver = { - .driver = { - .name = "gpio-vbus", - #ifdef CONFIG_PM - .pm = &gpio_vbus_dev_pm_ops, - #endif -+ .of_match_table = gpio_vbus_of_match, - }, - .probe = gpio_vbus_probe, - .remove = gpio_vbus_remove, diff --git a/target/linux/gemini/patches-6.1/0002-usb-fotg210-Collect-pieces-of-dual-mode-controller.patch b/target/linux/gemini/patches-6.1/0002-usb-fotg210-Collect-pieces-of-dual-mode-controller.patch deleted file mode 100644 index 1ee4f27c46d..00000000000 --- a/target/linux/gemini/patches-6.1/0002-usb-fotg210-Collect-pieces-of-dual-mode-controller.patch +++ /dev/null @@ -1,15990 +0,0 @@ -From 30367636930864f71b2bd462adedcf8484313864 Mon Sep 17 00:00:00 2001 -From: Linus Walleij -Date: Sun, 23 Oct 2022 16:47:06 +0200 -Subject: [PATCH 02/29] usb: fotg210: Collect pieces of dual mode controller - -The Faraday FOTG210 is a dual-mode OTG USB controller that can -act as host, peripheral or both. To be able to probe from one -hardware description and to follow the pattern of other dual- -mode controllers such as MUSB or MTU3 we need to collect the -two, currently completely separate drivers in the same -directory. - -After this, users need to select the main symbol USB_FOTG210 -and then each respective subdriver. We pave the road to -compile both drivers into the same kernel and select the -one we want to use at probe() time, and possibly add OTG -support in the end. - -This patch doesn't do much more than create the new symbol -and collect the drivers in one place. We also add a comment -for the section of dual-mode controllers in the Kconfig -file so people can see what these selections are about. - -Also add myself as maintainer as there has been little -response on my patches to these drivers. - -Cc: Fabian Vogt -Cc: Yuan-Hsin Chen -Cc: Felipe Balbi -Signed-off-by: Linus Walleij -Link: https://lore.kernel.org/r/20221023144708.3596563-1-linus.walleij@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- ---- a/drivers/usb/Kconfig -+++ b/drivers/usb/Kconfig -@@ -111,8 +111,12 @@ source "drivers/usb/usbip/Kconfig" - - endif - -+comment "USB dual-mode controller drivers" -+ - source "drivers/usb/cdns3/Kconfig" - -+source "drivers/usb/fotg210/Kconfig" -+ - source "drivers/usb/mtu3/Kconfig" - - source "drivers/usb/musb/Kconfig" ---- a/drivers/usb/Makefile -+++ b/drivers/usb/Makefile -@@ -17,6 +17,8 @@ obj-$(CONFIG_USB_CDNS_SUPPORT) += cdns3/ - obj-$(CONFIG_USB_CDNS3) += cdns3/ - obj-$(CONFIG_USB_CDNSP_PCI) += cdns3/ - -+obj-$(CONFIG_USB_FOTG210) += fotg210/ -+ - obj-$(CONFIG_USB_MON) += mon/ - obj-$(CONFIG_USB_MTU3) += mtu3/ - ---- /dev/null -+++ b/drivers/usb/fotg210/Kconfig -@@ -0,0 +1,36 @@ -+# SPDX-License-Identifier: GPL-2.0 -+ -+config USB_FOTG210 -+ tristate "Faraday FOTG210 USB2 Dual Role controller" -+ depends on USB || USB_GADGET -+ depends on HAS_DMA && HAS_IOMEM -+ default ARCH_GEMINI -+ help -+ Faraday FOTG210 is a dual-mode USB controller that can act -+ in both host controller and peripheral controller mode. -+ -+if USB_FOTG210 -+ -+config USB_FOTG210_HCD -+ tristate "Faraday FOTG210 USB Host Controller support" -+ depends on USB -+ help -+ Faraday FOTG210 is an OTG controller which can be configured as -+ an USB2.0 host. It is designed to meet USB2.0 EHCI specification -+ with minor modification. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called fotg210-hcd. -+ -+config USB_FOTG210_UDC -+ depends on USB_GADGET -+ tristate "Faraday FOTG210 USB Peripheral Controller support" -+ help -+ Faraday USB2.0 OTG controller which can be configured as -+ high speed or full speed USB device. This driver suppports -+ Bulk Transfer so far. -+ -+ Say "y" to link the driver statically, or "m" to build a -+ dynamically linked module called "fotg210-udc". -+ -+endif ---- /dev/null -+++ b/drivers/usb/fotg210/Makefile -@@ -0,0 +1,3 @@ -+# SPDX-License-Identifier: GPL-2.0 -+obj-$(CONFIG_USB_FOTG210_HCD) += fotg210-hcd.o -+obj-$(CONFIG_USB_FOTG210_UDC) += fotg210-udc.o ---- a/drivers/usb/host/fotg210-hcd.c -+++ /dev/null -@@ -1,5724 +0,0 @@ --// SPDX-License-Identifier: GPL-2.0+ --/* Faraday FOTG210 EHCI-like driver -- * -- * Copyright (c) 2013 Faraday Technology Corporation -- * -- * Author: Yuan-Hsin Chen -- * Feng-Hsin Chiang -- * Po-Yu Chuang -- * -- * Most of code borrowed from the Linux-3.7 EHCI driver -- */ --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include -- --#include --#include --#include -- --#define DRIVER_AUTHOR "Yuan-Hsin Chen" --#define DRIVER_DESC "FOTG210 Host Controller (EHCI) Driver" --static const char hcd_name[] = "fotg210_hcd"; -- --#undef FOTG210_URB_TRACE --#define FOTG210_STATS -- --/* magic numbers that can affect system performance */ --#define FOTG210_TUNE_CERR 3 /* 0-3 qtd retries; 0 == don't stop */ --#define FOTG210_TUNE_RL_HS 4 /* nak throttle; see 4.9 */ --#define FOTG210_TUNE_RL_TT 0 --#define FOTG210_TUNE_MULT_HS 1 /* 1-3 transactions/uframe; 4.10.3 */ --#define FOTG210_TUNE_MULT_TT 1 -- --/* Some drivers think it's safe to schedule isochronous transfers more than 256 -- * ms into the future (partly as a result of an old bug in the scheduling -- * code). In an attempt to avoid trouble, we will use a minimum scheduling -- * length of 512 frames instead of 256. -- */ --#define FOTG210_TUNE_FLS 1 /* (medium) 512-frame schedule */ -- --/* Initial IRQ latency: faster than hw default */ --static int log2_irq_thresh; /* 0 to 6 */ --module_param(log2_irq_thresh, int, S_IRUGO); --MODULE_PARM_DESC(log2_irq_thresh, "log2 IRQ latency, 1-64 microframes"); -- --/* initial park setting: slower than hw default */ --static unsigned park; --module_param(park, uint, S_IRUGO); --MODULE_PARM_DESC(park, "park setting; 1-3 back-to-back async packets"); -- --/* for link power management(LPM) feature */ --static unsigned int hird; --module_param(hird, int, S_IRUGO); --MODULE_PARM_DESC(hird, "host initiated resume duration, +1 for each 75us"); -- --#define INTR_MASK (STS_IAA | STS_FATAL | STS_PCD | STS_ERR | STS_INT) -- --#include "fotg210.h" -- --#define fotg210_dbg(fotg210, fmt, args...) \ -- dev_dbg(fotg210_to_hcd(fotg210)->self.controller, fmt, ## args) --#define fotg210_err(fotg210, fmt, args...) \ -- dev_err(fotg210_to_hcd(fotg210)->self.controller, fmt, ## args) --#define fotg210_info(fotg210, fmt, args...) \ -- dev_info(fotg210_to_hcd(fotg210)->self.controller, fmt, ## args) --#define fotg210_warn(fotg210, fmt, args...) \ -- dev_warn(fotg210_to_hcd(fotg210)->self.controller, fmt, ## args) -- --/* check the values in the HCSPARAMS register (host controller _Structural_ -- * parameters) see EHCI spec, Table 2-4 for each value -- */ --static void dbg_hcs_params(struct fotg210_hcd *fotg210, char *label) --{ -- u32 params = fotg210_readl(fotg210, &fotg210->caps->hcs_params); -- -- fotg210_dbg(fotg210, "%s hcs_params 0x%x ports=%d\n", label, params, -- HCS_N_PORTS(params)); --} -- --/* check the values in the HCCPARAMS register (host controller _Capability_ -- * parameters) see EHCI Spec, Table 2-5 for each value -- */ --static void dbg_hcc_params(struct fotg210_hcd *fotg210, char *label) --{ -- u32 params = fotg210_readl(fotg210, &fotg210->caps->hcc_params); -- -- fotg210_dbg(fotg210, "%s hcc_params %04x uframes %s%s\n", label, -- params, -- HCC_PGM_FRAMELISTLEN(params) ? "256/512/1024" : "1024", -- HCC_CANPARK(params) ? " park" : ""); --} -- --static void __maybe_unused --dbg_qtd(const char *label, struct fotg210_hcd *fotg210, struct fotg210_qtd *qtd) --{ -- fotg210_dbg(fotg210, "%s td %p n%08x %08x t%08x p0=%08x\n", label, qtd, -- hc32_to_cpup(fotg210, &qtd->hw_next), -- hc32_to_cpup(fotg210, &qtd->hw_alt_next), -- hc32_to_cpup(fotg210, &qtd->hw_token), -- hc32_to_cpup(fotg210, &qtd->hw_buf[0])); -- if (qtd->hw_buf[1]) -- fotg210_dbg(fotg210, " p1=%08x p2=%08x p3=%08x p4=%08x\n", -- hc32_to_cpup(fotg210, &qtd->hw_buf[1]), -- hc32_to_cpup(fotg210, &qtd->hw_buf[2]), -- hc32_to_cpup(fotg210, &qtd->hw_buf[3]), -- hc32_to_cpup(fotg210, &qtd->hw_buf[4])); --} -- --static void __maybe_unused --dbg_qh(const char *label, struct fotg210_hcd *fotg210, struct fotg210_qh *qh) --{ -- struct fotg210_qh_hw *hw = qh->hw; -- -- fotg210_dbg(fotg210, "%s qh %p n%08x info %x %x qtd %x\n", label, qh, -- hw->hw_next, hw->hw_info1, hw->hw_info2, -- hw->hw_current); -- -- dbg_qtd("overlay", fotg210, (struct fotg210_qtd *) &hw->hw_qtd_next); --} -- --static void __maybe_unused --dbg_itd(const char *label, struct fotg210_hcd *fotg210, struct fotg210_itd *itd) --{ -- fotg210_dbg(fotg210, "%s[%d] itd %p, next %08x, urb %p\n", label, -- itd->frame, itd, hc32_to_cpu(fotg210, itd->hw_next), -- itd->urb); -- -- fotg210_dbg(fotg210, -- " trans: %08x %08x %08x %08x %08x %08x %08x %08x\n", -- hc32_to_cpu(fotg210, itd->hw_transaction[0]), -- hc32_to_cpu(fotg210, itd->hw_transaction[1]), -- hc32_to_cpu(fotg210, itd->hw_transaction[2]), -- hc32_to_cpu(fotg210, itd->hw_transaction[3]), -- hc32_to_cpu(fotg210, itd->hw_transaction[4]), -- hc32_to_cpu(fotg210, itd->hw_transaction[5]), -- hc32_to_cpu(fotg210, itd->hw_transaction[6]), -- hc32_to_cpu(fotg210, itd->hw_transaction[7])); -- -- fotg210_dbg(fotg210, -- " buf: %08x %08x %08x %08x %08x %08x %08x\n", -- hc32_to_cpu(fotg210, itd->hw_bufp[0]), -- hc32_to_cpu(fotg210, itd->hw_bufp[1]), -- hc32_to_cpu(fotg210, itd->hw_bufp[2]), -- hc32_to_cpu(fotg210, itd->hw_bufp[3]), -- hc32_to_cpu(fotg210, itd->hw_bufp[4]), -- hc32_to_cpu(fotg210, itd->hw_bufp[5]), -- hc32_to_cpu(fotg210, itd->hw_bufp[6])); -- -- fotg210_dbg(fotg210, " index: %d %d %d %d %d %d %d %d\n", -- itd->index[0], itd->index[1], itd->index[2], -- itd->index[3], itd->index[4], itd->index[5], -- itd->index[6], itd->index[7]); --} -- --static int __maybe_unused --dbg_status_buf(char *buf, unsigned len, const char *label, u32 status) --{ -- return scnprintf(buf, len, "%s%sstatus %04x%s%s%s%s%s%s%s%s%s%s", -- label, label[0] ? " " : "", status, -- (status & STS_ASS) ? " Async" : "", -- (status & STS_PSS) ? " Periodic" : "", -- (status & STS_RECL) ? " Recl" : "", -- (status & STS_HALT) ? " Halt" : "", -- (status & STS_IAA) ? " IAA" : "", -- (status & STS_FATAL) ? " FATAL" : "", -- (status & STS_FLR) ? " FLR" : "", -- (status & STS_PCD) ? " PCD" : "", -- (status & STS_ERR) ? " ERR" : "", -- (status & STS_INT) ? " INT" : ""); --} -- --static int __maybe_unused --dbg_intr_buf(char *buf, unsigned len, const char *label, u32 enable) --{ -- return scnprintf(buf, len, "%s%sintrenable %02x%s%s%s%s%s%s", -- label, label[0] ? " " : "", enable, -- (enable & STS_IAA) ? " IAA" : "", -- (enable & STS_FATAL) ? " FATAL" : "", -- (enable & STS_FLR) ? " FLR" : "", -- (enable & STS_PCD) ? " PCD" : "", -- (enable & STS_ERR) ? " ERR" : "", -- (enable & STS_INT) ? " INT" : ""); --} -- --static const char *const fls_strings[] = { "1024", "512", "256", "??" }; -- --static int dbg_command_buf(char *buf, unsigned len, const char *label, -- u32 command) --{ -- return scnprintf(buf, len, -- "%s%scommand %07x %s=%d ithresh=%d%s%s%s period=%s%s %s", -- label, label[0] ? " " : "", command, -- (command & CMD_PARK) ? " park" : "(park)", -- CMD_PARK_CNT(command), -- (command >> 16) & 0x3f, -- (command & CMD_IAAD) ? " IAAD" : "", -- (command & CMD_ASE) ? " Async" : "", -- (command & CMD_PSE) ? " Periodic" : "", -- fls_strings[(command >> 2) & 0x3], -- (command & CMD_RESET) ? " Reset" : "", -- (command & CMD_RUN) ? "RUN" : "HALT"); --} -- --static char *dbg_port_buf(char *buf, unsigned len, const char *label, int port, -- u32 status) --{ -- char *sig; -- -- /* signaling state */ -- switch (status & (3 << 10)) { -- case 0 << 10: -- sig = "se0"; -- break; -- case 1 << 10: -- sig = "k"; -- break; /* low speed */ -- case 2 << 10: -- sig = "j"; -- break; -- default: -- sig = "?"; -- break; -- } -- -- scnprintf(buf, len, "%s%sport:%d status %06x %d sig=%s%s%s%s%s%s%s%s", -- label, label[0] ? " " : "", port, status, -- status >> 25, /*device address */ -- sig, -- (status & PORT_RESET) ? " RESET" : "", -- (status & PORT_SUSPEND) ? " SUSPEND" : "", -- (status & PORT_RESUME) ? " RESUME" : "", -- (status & PORT_PEC) ? " PEC" : "", -- (status & PORT_PE) ? " PE" : "", -- (status & PORT_CSC) ? " CSC" : "", -- (status & PORT_CONNECT) ? " CONNECT" : ""); -- -- return buf; --} -- --/* functions have the "wrong" filename when they're output... */ --#define dbg_status(fotg210, label, status) { \ -- char _buf[80]; \ -- dbg_status_buf(_buf, sizeof(_buf), label, status); \ -- fotg210_dbg(fotg210, "%s\n", _buf); \ --} -- --#define dbg_cmd(fotg210, label, command) { \ -- char _buf[80]; \ -- dbg_command_buf(_buf, sizeof(_buf), label, command); \ -- fotg210_dbg(fotg210, "%s\n", _buf); \ --} -- --#define dbg_port(fotg210, label, port, status) { \ -- char _buf[80]; \ -- fotg210_dbg(fotg210, "%s\n", \ -- dbg_port_buf(_buf, sizeof(_buf), label, port, status));\ --} -- --/* troubleshooting help: expose state in debugfs */ --static int debug_async_open(struct inode *, struct file *); --static int debug_periodic_open(struct inode *, struct file *); --static int debug_registers_open(struct inode *, struct file *); --static int debug_async_open(struct inode *, struct file *); -- --static ssize_t debug_output(struct file*, char __user*, size_t, loff_t*); --static int debug_close(struct inode *, struct file *); -- --static const struct file_operations debug_async_fops = { -- .owner = THIS_MODULE, -- .open = debug_async_open, -- .read = debug_output, -- .release = debug_close, -- .llseek = default_llseek, --}; --static const struct file_operations debug_periodic_fops = { -- .owner = THIS_MODULE, -- .open = debug_periodic_open, -- .read = debug_output, -- .release = debug_close, -- .llseek = default_llseek, --}; --static const struct file_operations debug_registers_fops = { -- .owner = THIS_MODULE, -- .open = debug_registers_open, -- .read = debug_output, -- .release = debug_close, -- .llseek = default_llseek, --}; -- --static struct dentry *fotg210_debug_root; -- --struct debug_buffer { -- ssize_t (*fill_func)(struct debug_buffer *); /* fill method */ -- struct usb_bus *bus; -- struct mutex mutex; /* protect filling of buffer */ -- size_t count; /* number of characters filled into buffer */ -- char *output_buf; -- size_t alloc_size; --}; -- --static inline char speed_char(u32 scratch) --{ -- switch (scratch & (3 << 12)) { -- case QH_FULL_SPEED: -- return 'f'; -- -- case QH_LOW_SPEED: -- return 'l'; -- -- case QH_HIGH_SPEED: -- return 'h'; -- -- default: -- return '?'; -- } --} -- --static inline char token_mark(struct fotg210_hcd *fotg210, __hc32 token) --{ -- __u32 v = hc32_to_cpu(fotg210, token); -- -- if (v & QTD_STS_ACTIVE) -- return '*'; -- if (v & QTD_STS_HALT) -- return '-'; -- if (!IS_SHORT_READ(v)) -- return ' '; -- /* tries to advance through hw_alt_next */ -- return '/'; --} -- --static void qh_lines(struct fotg210_hcd *fotg210, struct fotg210_qh *qh, -- char **nextp, unsigned *sizep) --{ -- u32 scratch; -- u32 hw_curr; -- struct fotg210_qtd *td; -- unsigned temp; -- unsigned size = *sizep; -- char *next = *nextp; -- char mark; -- __le32 list_end = FOTG210_LIST_END(fotg210); -- struct fotg210_qh_hw *hw = qh->hw; -- -- if (hw->hw_qtd_next == list_end) /* NEC does this */ -- mark = '@'; -- else -- mark = token_mark(fotg210, hw->hw_token); -- if (mark == '/') { /* qh_alt_next controls qh advance? */ -- if ((hw->hw_alt_next & QTD_MASK(fotg210)) == -- fotg210->async->hw->hw_alt_next) -- mark = '#'; /* blocked */ -- else if (hw->hw_alt_next == list_end) -- mark = '.'; /* use hw_qtd_next */ -- /* else alt_next points to some other qtd */ -- } -- scratch = hc32_to_cpup(fotg210, &hw->hw_info1); -- hw_curr = (mark == '*') ? hc32_to_cpup(fotg210, &hw->hw_current) : 0; -- temp = scnprintf(next, size, -- "qh/%p dev%d %cs ep%d %08x %08x(%08x%c %s nak%d)", -- qh, scratch & 0x007f, -- speed_char(scratch), -- (scratch >> 8) & 0x000f, -- scratch, hc32_to_cpup(fotg210, &hw->hw_info2), -- hc32_to_cpup(fotg210, &hw->hw_token), mark, -- (cpu_to_hc32(fotg210, QTD_TOGGLE) & hw->hw_token) -- ? "data1" : "data0", -- (hc32_to_cpup(fotg210, &hw->hw_alt_next) >> 1) & 0x0f); -- size -= temp; -- next += temp; -- -- /* hc may be modifying the list as we read it ... */ -- list_for_each_entry(td, &qh->qtd_list, qtd_list) { -- scratch = hc32_to_cpup(fotg210, &td->hw_token); -- mark = ' '; -- if (hw_curr == td->qtd_dma) -- mark = '*'; -- else if (hw->hw_qtd_next == cpu_to_hc32(fotg210, td->qtd_dma)) -- mark = '+'; -- else if (QTD_LENGTH(scratch)) { -- if (td->hw_alt_next == fotg210->async->hw->hw_alt_next) -- mark = '#'; -- else if (td->hw_alt_next != list_end) -- mark = '/'; -- } -- temp = snprintf(next, size, -- "\n\t%p%c%s len=%d %08x urb %p", -- td, mark, ({ char *tmp; -- switch ((scratch>>8)&0x03) { -- case 0: -- tmp = "out"; -- break; -- case 1: -- tmp = "in"; -- break; -- case 2: -- tmp = "setup"; -- break; -- default: -- tmp = "?"; -- break; -- } tmp; }), -- (scratch >> 16) & 0x7fff, -- scratch, -- td->urb); -- if (size < temp) -- temp = size; -- size -= temp; -- next += temp; -- } -- -- temp = snprintf(next, size, "\n"); -- if (size < temp) -- temp = size; -- -- size -= temp; -- next += temp; -- -- *sizep = size; -- *nextp = next; --} -- --static ssize_t fill_async_buffer(struct debug_buffer *buf) --{ -- struct usb_hcd *hcd; -- struct fotg210_hcd *fotg210; -- unsigned long flags; -- unsigned temp, size; -- char *next; -- struct fotg210_qh *qh; -- -- hcd = bus_to_hcd(buf->bus); -- fotg210 = hcd_to_fotg210(hcd); -- next = buf->output_buf; -- size = buf->alloc_size; -- -- *next = 0; -- -- /* dumps a snapshot of the async schedule. -- * usually empty except for long-term bulk reads, or head. -- * one QH per line, and TDs we know about -- */ -- spin_lock_irqsave(&fotg210->lock, flags); -- for (qh = fotg210->async->qh_next.qh; size > 0 && qh; -- qh = qh->qh_next.qh) -- qh_lines(fotg210, qh, &next, &size); -- if (fotg210->async_unlink && size > 0) { -- temp = scnprintf(next, size, "\nunlink =\n"); -- size -= temp; -- next += temp; -- -- for (qh = fotg210->async_unlink; size > 0 && qh; -- qh = qh->unlink_next) -- qh_lines(fotg210, qh, &next, &size); -- } -- spin_unlock_irqrestore(&fotg210->lock, flags); -- -- return strlen(buf->output_buf); --} -- --/* count tds, get ep direction */ --static unsigned output_buf_tds_dir(char *buf, struct fotg210_hcd *fotg210, -- struct fotg210_qh_hw *hw, struct fotg210_qh *qh, unsigned size) --{ -- u32 scratch = hc32_to_cpup(fotg210, &hw->hw_info1); -- struct fotg210_qtd *qtd; -- char *type = ""; -- unsigned temp = 0; -- -- /* count tds, get ep direction */ -- list_for_each_entry(qtd, &qh->qtd_list, qtd_list) { -- temp++; -- switch ((hc32_to_cpu(fotg210, qtd->hw_token) >> 8) & 0x03) { -- case 0: -- type = "out"; -- continue; -- case 1: -- type = "in"; -- continue; -- } -- } -- -- return scnprintf(buf, size, "(%c%d ep%d%s [%d/%d] q%d p%d)", -- speed_char(scratch), scratch & 0x007f, -- (scratch >> 8) & 0x000f, type, qh->usecs, -- qh->c_usecs, temp, (scratch >> 16) & 0x7ff); --} -- --#define DBG_SCHED_LIMIT 64 --static ssize_t fill_periodic_buffer(struct debug_buffer *buf) --{ -- struct usb_hcd *hcd; -- struct fotg210_hcd *fotg210; -- unsigned long flags; -- union fotg210_shadow p, *seen; -- unsigned temp, size, seen_count; -- char *next; -- unsigned i; -- __hc32 tag; -- -- seen = kmalloc_array(DBG_SCHED_LIMIT, sizeof(*seen), GFP_ATOMIC); -- if (!seen) -- return 0; -- -- seen_count = 0; -- -- hcd = bus_to_hcd(buf->bus); -- fotg210 = hcd_to_fotg210(hcd); -- next = buf->output_buf; -- size = buf->alloc_size; -- -- temp = scnprintf(next, size, "size = %d\n", fotg210->periodic_size); -- size -= temp; -- next += temp; -- -- /* dump a snapshot of the periodic schedule. -- * iso changes, interrupt usually doesn't. -- */ -- spin_lock_irqsave(&fotg210->lock, flags); -- for (i = 0; i < fotg210->periodic_size; i++) { -- p = fotg210->pshadow[i]; -- if (likely(!p.ptr)) -- continue; -- -- tag = Q_NEXT_TYPE(fotg210, fotg210->periodic[i]); -- -- temp = scnprintf(next, size, "%4d: ", i); -- size -= temp; -- next += temp; -- -- do { -- struct fotg210_qh_hw *hw; -- -- switch (hc32_to_cpu(fotg210, tag)) { -- case Q_TYPE_QH: -- hw = p.qh->hw; -- temp = scnprintf(next, size, " qh%d-%04x/%p", -- p.qh->period, -- hc32_to_cpup(fotg210, -- &hw->hw_info2) -- /* uframe masks */ -- & (QH_CMASK | QH_SMASK), -- p.qh); -- size -= temp; -- next += temp; -- /* don't repeat what follows this qh */ -- for (temp = 0; temp < seen_count; temp++) { -- if (seen[temp].ptr != p.ptr) -- continue; -- if (p.qh->qh_next.ptr) { -- temp = scnprintf(next, size, -- " ..."); -- size -= temp; -- next += temp; -- } -- break; -- } -- /* show more info the first time around */ -- if (temp == seen_count) { -- temp = output_buf_tds_dir(next, -- fotg210, hw, -- p.qh, size); -- -- if (seen_count < DBG_SCHED_LIMIT) -- seen[seen_count++].qh = p.qh; -- } else -- temp = 0; -- tag = Q_NEXT_TYPE(fotg210, hw->hw_next); -- p = p.qh->qh_next; -- break; -- case Q_TYPE_FSTN: -- temp = scnprintf(next, size, -- " fstn-%8x/%p", -- p.fstn->hw_prev, p.fstn); -- tag = Q_NEXT_TYPE(fotg210, p.fstn->hw_next); -- p = p.fstn->fstn_next; -- break; -- case Q_TYPE_ITD: -- temp = scnprintf(next, size, -- " itd/%p", p.itd); -- tag = Q_NEXT_TYPE(fotg210, p.itd->hw_next); -- p = p.itd->itd_next; -- break; -- } -- size -= temp; -- next += temp; -- } while (p.ptr); -- -- temp = scnprintf(next, size, "\n"); -- size -= temp; -- next += temp; -- } -- spin_unlock_irqrestore(&fotg210->lock, flags); -- kfree(seen); -- -- return buf->alloc_size - size; --} --#undef DBG_SCHED_LIMIT -- --static const char *rh_state_string(struct fotg210_hcd *fotg210) --{ -- switch (fotg210->rh_state) { -- case FOTG210_RH_HALTED: -- return "halted"; -- case FOTG210_RH_SUSPENDED: -- return "suspended"; -- case FOTG210_RH_RUNNING: -- return "running"; -- case FOTG210_RH_STOPPING: -- return "stopping"; -- } -- return "?"; --} -- --static ssize_t fill_registers_buffer(struct debug_buffer *buf) --{ -- struct usb_hcd *hcd; -- struct fotg210_hcd *fotg210; -- unsigned long flags; -- unsigned temp, size, i; -- char *next, scratch[80]; -- static const char fmt[] = "%*s\n"; -- static const char label[] = ""; -- -- hcd = bus_to_hcd(buf->bus); -- fotg210 = hcd_to_fotg210(hcd); -- next = buf->output_buf; -- size = buf->alloc_size; -- -- spin_lock_irqsave(&fotg210->lock, flags); -- -- if (!HCD_HW_ACCESSIBLE(hcd)) { -- size = scnprintf(next, size, -- "bus %s, device %s\n" -- "%s\n" -- "SUSPENDED(no register access)\n", -- hcd->self.controller->bus->name, -- dev_name(hcd->self.controller), -- hcd->product_desc); -- goto done; -- } -- -- /* Capability Registers */ -- i = HC_VERSION(fotg210, fotg210_readl(fotg210, -- &fotg210->caps->hc_capbase)); -- temp = scnprintf(next, size, -- "bus %s, device %s\n" -- "%s\n" -- "EHCI %x.%02x, rh state %s\n", -- hcd->self.controller->bus->name, -- dev_name(hcd->self.controller), -- hcd->product_desc, -- i >> 8, i & 0x0ff, rh_state_string(fotg210)); -- size -= temp; -- next += temp; -- -- /* FIXME interpret both types of params */ -- i = fotg210_readl(fotg210, &fotg210->caps->hcs_params); -- temp = scnprintf(next, size, "structural params 0x%08x\n", i); -- size -= temp; -- next += temp; -- -- i = fotg210_readl(fotg210, &fotg210->caps->hcc_params); -- temp = scnprintf(next, size, "capability params 0x%08x\n", i); -- size -= temp; -- next += temp; -- -- /* Operational Registers */ -- temp = dbg_status_buf(scratch, sizeof(scratch), label, -- fotg210_readl(fotg210, &fotg210->regs->status)); -- temp = scnprintf(next, size, fmt, temp, scratch); -- size -= temp; -- next += temp; -- -- temp = dbg_command_buf(scratch, sizeof(scratch), label, -- fotg210_readl(fotg210, &fotg210->regs->command)); -- temp = scnprintf(next, size, fmt, temp, scratch); -- size -= temp; -- next += temp; -- -- temp = dbg_intr_buf(scratch, sizeof(scratch), label, -- fotg210_readl(fotg210, &fotg210->regs->intr_enable)); -- temp = scnprintf(next, size, fmt, temp, scratch); -- size -= temp; -- next += temp; -- -- temp = scnprintf(next, size, "uframe %04x\n", -- fotg210_read_frame_index(fotg210)); -- size -= temp; -- next += temp; -- -- if (fotg210->async_unlink) { -- temp = scnprintf(next, size, "async unlink qh %p\n", -- fotg210->async_unlink); -- size -= temp; -- next += temp; -- } -- --#ifdef FOTG210_STATS -- temp = scnprintf(next, size, -- "irq normal %ld err %ld iaa %ld(lost %ld)\n", -- fotg210->stats.normal, fotg210->stats.error, -- fotg210->stats.iaa, fotg210->stats.lost_iaa); -- size -= temp; -- next += temp; -- -- temp = scnprintf(next, size, "complete %ld unlink %ld\n", -- fotg210->stats.complete, fotg210->stats.unlink); -- size -= temp; -- next += temp; --#endif -- --done: -- spin_unlock_irqrestore(&fotg210->lock, flags); -- -- return buf->alloc_size - size; --} -- --static struct debug_buffer --*alloc_buffer(struct usb_bus *bus, ssize_t (*fill_func)(struct debug_buffer *)) --{ -- struct debug_buffer *buf; -- -- buf = kzalloc(sizeof(struct debug_buffer), GFP_KERNEL); -- -- if (buf) { -- buf->bus = bus; -- buf->fill_func = fill_func; -- mutex_init(&buf->mutex); -- buf->alloc_size = PAGE_SIZE; -- } -- -- return buf; --} -- --static int fill_buffer(struct debug_buffer *buf) --{ -- int ret = 0; -- -- if (!buf->output_buf) -- buf->output_buf = vmalloc(buf->alloc_size); -- -- if (!buf->output_buf) { -- ret = -ENOMEM; -- goto out; -- } -- -- ret = buf->fill_func(buf); -- -- if (ret >= 0) { -- buf->count = ret; -- ret = 0; -- } -- --out: -- return ret; --} -- --static ssize_t debug_output(struct file *file, char __user *user_buf, -- size_t len, loff_t *offset) --{ -- struct debug_buffer *buf = file->private_data; -- int ret = 0; -- -- mutex_lock(&buf->mutex); -- if (buf->count == 0) { -- ret = fill_buffer(buf); -- if (ret != 0) { -- mutex_unlock(&buf->mutex); -- goto out; -- } -- } -- mutex_unlock(&buf->mutex); -- -- ret = simple_read_from_buffer(user_buf, len, offset, -- buf->output_buf, buf->count); -- --out: -- return ret; -- --} -- --static int debug_close(struct inode *inode, struct file *file) --{ -- struct debug_buffer *buf = file->private_data; -- -- if (buf) { -- vfree(buf->output_buf); -- kfree(buf); -- } -- -- return 0; --} --static int debug_async_open(struct inode *inode, struct file *file) --{ -- file->private_data = alloc_buffer(inode->i_private, fill_async_buffer); -- -- return file->private_data ? 0 : -ENOMEM; --} -- --static int debug_periodic_open(struct inode *inode, struct file *file) --{ -- struct debug_buffer *buf; -- -- buf = alloc_buffer(inode->i_private, fill_periodic_buffer); -- if (!buf) -- return -ENOMEM; -- -- buf->alloc_size = (sizeof(void *) == 4 ? 6 : 8)*PAGE_SIZE; -- file->private_data = buf; -- return 0; --} -- --static int debug_registers_open(struct inode *inode, struct file *file) --{ -- file->private_data = alloc_buffer(inode->i_private, -- fill_registers_buffer); -- -- return file->private_data ? 0 : -ENOMEM; --} -- --static inline void create_debug_files(struct fotg210_hcd *fotg210) --{ -- struct usb_bus *bus = &fotg210_to_hcd(fotg210)->self; -- struct dentry *root; -- -- root = debugfs_create_dir(bus->bus_name, fotg210_debug_root); -- -- debugfs_create_file("async", S_IRUGO, root, bus, &debug_async_fops); -- debugfs_create_file("periodic", S_IRUGO, root, bus, -- &debug_periodic_fops); -- debugfs_create_file("registers", S_IRUGO, root, bus, -- &debug_registers_fops); --} -- --static inline void remove_debug_files(struct fotg210_hcd *fotg210) --{ -- struct usb_bus *bus = &fotg210_to_hcd(fotg210)->self; -- -- debugfs_lookup_and_remove(bus->bus_name, fotg210_debug_root); --} -- --/* handshake - spin reading hc until handshake completes or fails -- * @ptr: address of hc register to be read -- * @mask: bits to look at in result of read -- * @done: value of those bits when handshake succeeds -- * @usec: timeout in microseconds -- * -- * Returns negative errno, or zero on success -- * -- * Success happens when the "mask" bits have the specified value (hardware -- * handshake done). There are two failure modes: "usec" have passed (major -- * hardware flakeout), or the register reads as all-ones (hardware removed). -- * -- * That last failure should_only happen in cases like physical cardbus eject -- * before driver shutdown. But it also seems to be caused by bugs in cardbus -- * bridge shutdown: shutting down the bridge before the devices using it. -- */ --static int handshake(struct fotg210_hcd *fotg210, void __iomem *ptr, -- u32 mask, u32 done, int usec) --{ -- u32 result; -- int ret; -- -- ret = readl_poll_timeout_atomic(ptr, result, -- ((result & mask) == done || -- result == U32_MAX), 1, usec); -- if (result == U32_MAX) /* card removed */ -- return -ENODEV; -- -- return ret; --} -- --/* Force HC to halt state from unknown (EHCI spec section 2.3). -- * Must be called with interrupts enabled and the lock not held. -- */ --static int fotg210_halt(struct fotg210_hcd *fotg210) --{ -- u32 temp; -- -- spin_lock_irq(&fotg210->lock); -- -- /* disable any irqs left enabled by previous code */ -- fotg210_writel(fotg210, 0, &fotg210->regs->intr_enable); -- -- /* -- * This routine gets called during probe before fotg210->command -- * has been initialized, so we can't rely on its value. -- */ -- fotg210->command &= ~CMD_RUN; -- temp = fotg210_readl(fotg210, &fotg210->regs->command); -- temp &= ~(CMD_RUN | CMD_IAAD); -- fotg210_writel(fotg210, temp, &fotg210->regs->command); -- -- spin_unlock_irq(&fotg210->lock); -- synchronize_irq(fotg210_to_hcd(fotg210)->irq); -- -- return handshake(fotg210, &fotg210->regs->status, -- STS_HALT, STS_HALT, 16 * 125); --} -- --/* Reset a non-running (STS_HALT == 1) controller. -- * Must be called with interrupts enabled and the lock not held. -- */ --static int fotg210_reset(struct fotg210_hcd *fotg210) --{ -- int retval; -- u32 command = fotg210_readl(fotg210, &fotg210->regs->command); -- -- /* If the EHCI debug controller is active, special care must be -- * taken before and after a host controller reset -- */ -- if (fotg210->debug && !dbgp_reset_prep(fotg210_to_hcd(fotg210))) -- fotg210->debug = NULL; -- -- command |= CMD_RESET; -- dbg_cmd(fotg210, "reset", command); -- fotg210_writel(fotg210, command, &fotg210->regs->command); -- fotg210->rh_state = FOTG210_RH_HALTED; -- fotg210->next_statechange = jiffies; -- retval = handshake(fotg210, &fotg210->regs->command, -- CMD_RESET, 0, 250 * 1000); -- -- if (retval) -- return retval; -- -- if (fotg210->debug) -- dbgp_external_startup(fotg210_to_hcd(fotg210)); -- -- fotg210->port_c_suspend = fotg210->suspended_ports = -- fotg210->resuming_ports = 0; -- return retval; --} -- --/* Idle the controller (turn off the schedules). -- * Must be called with interrupts enabled and the lock not held. -- */ --static void fotg210_quiesce(struct fotg210_hcd *fotg210) --{ -- u32 temp; -- -- if (fotg210->rh_state != FOTG210_RH_RUNNING) -- return; -- -- /* wait for any schedule enables/disables to take effect */ -- temp = (fotg210->command << 10) & (STS_ASS | STS_PSS); -- handshake(fotg210, &fotg210->regs->status, STS_ASS | STS_PSS, temp, -- 16 * 125); -- -- /* then disable anything that's still active */ -- spin_lock_irq(&fotg210->lock); -- fotg210->command &= ~(CMD_ASE | CMD_PSE); -- fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command); -- spin_unlock_irq(&fotg210->lock); -- -- /* hardware can take 16 microframes to turn off ... */ -- handshake(fotg210, &fotg210->regs->status, STS_ASS | STS_PSS, 0, -- 16 * 125); --} -- --static void end_unlink_async(struct fotg210_hcd *fotg210); --static void unlink_empty_async(struct fotg210_hcd *fotg210); --static void fotg210_work(struct fotg210_hcd *fotg210); --static void start_unlink_intr(struct fotg210_hcd *fotg210, -- struct fotg210_qh *qh); --static void end_unlink_intr(struct fotg210_hcd *fotg210, struct fotg210_qh *qh); -- --/* Set a bit in the USBCMD register */ --static void fotg210_set_command_bit(struct fotg210_hcd *fotg210, u32 bit) --{ -- fotg210->command |= bit; -- fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command); -- -- /* unblock posted write */ -- fotg210_readl(fotg210, &fotg210->regs->command); --} -- --/* Clear a bit in the USBCMD register */ --static void fotg210_clear_command_bit(struct fotg210_hcd *fotg210, u32 bit) --{ -- fotg210->command &= ~bit; -- fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command); -- -- /* unblock posted write */ -- fotg210_readl(fotg210, &fotg210->regs->command); --} -- --/* EHCI timer support... Now using hrtimers. -- * -- * Lots of different events are triggered from fotg210->hrtimer. Whenever -- * the timer routine runs, it checks each possible event; events that are -- * currently enabled and whose expiration time has passed get handled. -- * The set of enabled events is stored as a collection of bitflags in -- * fotg210->enabled_hrtimer_events, and they are numbered in order of -- * increasing delay values (ranging between 1 ms and 100 ms). -- * -- * Rather than implementing a sorted list or tree of all pending events, -- * we keep track only of the lowest-numbered pending event, in -- * fotg210->next_hrtimer_event. Whenever fotg210->hrtimer gets restarted, its -- * expiration time is set to the timeout value for this event. -- * -- * As a result, events might not get handled right away; the actual delay -- * could be anywhere up to twice the requested delay. This doesn't -- * matter, because none of the events are especially time-critical. The -- * ones that matter most all have a delay of 1 ms, so they will be -- * handled after 2 ms at most, which is okay. In addition to this, we -- * allow for an expiration range of 1 ms. -- */ -- --/* Delay lengths for the hrtimer event types. -- * Keep this list sorted by delay length, in the same order as -- * the event types indexed by enum fotg210_hrtimer_event in fotg210.h. -- */ --static unsigned event_delays_ns[] = { -- 1 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_POLL_ASS */ -- 1 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_POLL_PSS */ -- 1 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_POLL_DEAD */ -- 1125 * NSEC_PER_USEC, /* FOTG210_HRTIMER_UNLINK_INTR */ -- 2 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_FREE_ITDS */ -- 6 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_ASYNC_UNLINKS */ -- 10 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_IAA_WATCHDOG */ -- 10 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_DISABLE_PERIODIC */ -- 15 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_DISABLE_ASYNC */ -- 100 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_IO_WATCHDOG */ --}; -- --/* Enable a pending hrtimer event */ --static void fotg210_enable_event(struct fotg210_hcd *fotg210, unsigned event, -- bool resched) --{ -- ktime_t *timeout = &fotg210->hr_timeouts[event]; -- -- if (resched) -- *timeout = ktime_add(ktime_get(), event_delays_ns[event]); -- fotg210->enabled_hrtimer_events |= (1 << event); -- -- /* Track only the lowest-numbered pending event */ -- if (event < fotg210->next_hrtimer_event) { -- fotg210->next_hrtimer_event = event; -- hrtimer_start_range_ns(&fotg210->hrtimer, *timeout, -- NSEC_PER_MSEC, HRTIMER_MODE_ABS); -- } --} -- -- --/* Poll the STS_ASS status bit; see when it agrees with CMD_ASE */ --static void fotg210_poll_ASS(struct fotg210_hcd *fotg210) --{ -- unsigned actual, want; -- -- /* Don't enable anything if the controller isn't running (e.g., died) */ -- if (fotg210->rh_state != FOTG210_RH_RUNNING) -- return; -- -- want = (fotg210->command & CMD_ASE) ? STS_ASS : 0; -- actual = fotg210_readl(fotg210, &fotg210->regs->status) & STS_ASS; -- -- if (want != actual) { -- -- /* Poll again later, but give up after about 20 ms */ -- if (fotg210->ASS_poll_count++ < 20) { -- fotg210_enable_event(fotg210, FOTG210_HRTIMER_POLL_ASS, -- true); -- return; -- } -- fotg210_dbg(fotg210, "Waited too long for the async schedule status (%x/%x), giving up\n", -- want, actual); -- } -- fotg210->ASS_poll_count = 0; -- -- /* The status is up-to-date; restart or stop the schedule as needed */ -- if (want == 0) { /* Stopped */ -- if (fotg210->async_count > 0) -- fotg210_set_command_bit(fotg210, CMD_ASE); -- -- } else { /* Running */ -- if (fotg210->async_count == 0) { -- -- /* Turn off the schedule after a while */ -- fotg210_enable_event(fotg210, -- FOTG210_HRTIMER_DISABLE_ASYNC, -- true); -- } -- } --} -- --/* Turn off the async schedule after a brief delay */ --static void fotg210_disable_ASE(struct fotg210_hcd *fotg210) --{ -- fotg210_clear_command_bit(fotg210, CMD_ASE); --} -- -- --/* Poll the STS_PSS status bit; see when it agrees with CMD_PSE */ --static void fotg210_poll_PSS(struct fotg210_hcd *fotg210) --{ -- unsigned actual, want; -- -- /* Don't do anything if the controller isn't running (e.g., died) */ -- if (fotg210->rh_state != FOTG210_RH_RUNNING) -- return; -- -- want = (fotg210->command & CMD_PSE) ? STS_PSS : 0; -- actual = fotg210_readl(fotg210, &fotg210->regs->status) & STS_PSS; -- -- if (want != actual) { -- -- /* Poll again later, but give up after about 20 ms */ -- if (fotg210->PSS_poll_count++ < 20) { -- fotg210_enable_event(fotg210, FOTG210_HRTIMER_POLL_PSS, -- true); -- return; -- } -- fotg210_dbg(fotg210, "Waited too long for the periodic schedule status (%x/%x), giving up\n", -- want, actual); -- } -- fotg210->PSS_poll_count = 0; -- -- /* The status is up-to-date; restart or stop the schedule as needed */ -- if (want == 0) { /* Stopped */ -- if (fotg210->periodic_count > 0) -- fotg210_set_command_bit(fotg210, CMD_PSE); -- -- } else { /* Running */ -- if (fotg210->periodic_count == 0) { -- -- /* Turn off the schedule after a while */ -- fotg210_enable_event(fotg210, -- FOTG210_HRTIMER_DISABLE_PERIODIC, -- true); -- } -- } --} -- --/* Turn off the periodic schedule after a brief delay */ --static void fotg210_disable_PSE(struct fotg210_hcd *fotg210) --{ -- fotg210_clear_command_bit(fotg210, CMD_PSE); --} -- -- --/* Poll the STS_HALT status bit; see when a dead controller stops */ --static void fotg210_handle_controller_death(struct fotg210_hcd *fotg210) --{ -- if (!(fotg210_readl(fotg210, &fotg210->regs->status) & STS_HALT)) { -- -- /* Give up after a few milliseconds */ -- if (fotg210->died_poll_count++ < 5) { -- /* Try again later */ -- fotg210_enable_event(fotg210, -- FOTG210_HRTIMER_POLL_DEAD, true); -- return; -- } -- fotg210_warn(fotg210, "Waited too long for the controller to stop, giving up\n"); -- } -- -- /* Clean up the mess */ -- fotg210->rh_state = FOTG210_RH_HALTED; -- fotg210_writel(fotg210, 0, &fotg210->regs->intr_enable); -- fotg210_work(fotg210); -- end_unlink_async(fotg210); -- -- /* Not in process context, so don't try to reset the controller */ --} -- -- --/* Handle unlinked interrupt QHs once they are gone from the hardware */ --static void fotg210_handle_intr_unlinks(struct fotg210_hcd *fotg210) --{ -- bool stopped = (fotg210->rh_state < FOTG210_RH_RUNNING); -- -- /* -- * Process all the QHs on the intr_unlink list that were added -- * before the current unlink cycle began. The list is in -- * temporal order, so stop when we reach the first entry in the -- * current cycle. But if the root hub isn't running then -- * process all the QHs on the list. -- */ -- fotg210->intr_unlinking = true; -- while (fotg210->intr_unlink) { -- struct fotg210_qh *qh = fotg210->intr_unlink; -- -- if (!stopped && qh->unlink_cycle == fotg210->intr_unlink_cycle) -- break; -- fotg210->intr_unlink = qh->unlink_next; -- qh->unlink_next = NULL; -- end_unlink_intr(fotg210, qh); -- } -- -- /* Handle remaining entries later */ -- if (fotg210->intr_unlink) { -- fotg210_enable_event(fotg210, FOTG210_HRTIMER_UNLINK_INTR, -- true); -- ++fotg210->intr_unlink_cycle; -- } -- fotg210->intr_unlinking = false; --} -- -- --/* Start another free-iTDs/siTDs cycle */ --static void start_free_itds(struct fotg210_hcd *fotg210) --{ -- if (!(fotg210->enabled_hrtimer_events & -- BIT(FOTG210_HRTIMER_FREE_ITDS))) { -- fotg210->last_itd_to_free = list_entry( -- fotg210->cached_itd_list.prev, -- struct fotg210_itd, itd_list); -- fotg210_enable_event(fotg210, FOTG210_HRTIMER_FREE_ITDS, true); -- } --} -- --/* Wait for controller to stop using old iTDs and siTDs */ --static void end_free_itds(struct fotg210_hcd *fotg210) --{ -- struct fotg210_itd *itd, *n; -- -- if (fotg210->rh_state < FOTG210_RH_RUNNING) -- fotg210->last_itd_to_free = NULL; -- -- list_for_each_entry_safe(itd, n, &fotg210->cached_itd_list, itd_list) { -- list_del(&itd->itd_list); -- dma_pool_free(fotg210->itd_pool, itd, itd->itd_dma); -- if (itd == fotg210->last_itd_to_free) -- break; -- } -- -- if (!list_empty(&fotg210->cached_itd_list)) -- start_free_itds(fotg210); --} -- -- --/* Handle lost (or very late) IAA interrupts */ --static void fotg210_iaa_watchdog(struct fotg210_hcd *fotg210) --{ -- if (fotg210->rh_state != FOTG210_RH_RUNNING) -- return; -- -- /* -- * Lost IAA irqs wedge things badly; seen first with a vt8235. -- * So we need this watchdog, but must protect it against both -- * (a) SMP races against real IAA firing and retriggering, and -- * (b) clean HC shutdown, when IAA watchdog was pending. -- */ -- if (fotg210->async_iaa) { -- u32 cmd, status; -- -- /* If we get here, IAA is *REALLY* late. It's barely -- * conceivable that the system is so busy that CMD_IAAD -- * is still legitimately set, so let's be sure it's -- * clear before we read STS_IAA. (The HC should clear -- * CMD_IAAD when it sets STS_IAA.) -- */ -- cmd = fotg210_readl(fotg210, &fotg210->regs->command); -- -- /* -- * If IAA is set here it either legitimately triggered -- * after the watchdog timer expired (_way_ late, so we'll -- * still count it as lost) ... or a silicon erratum: -- * - VIA seems to set IAA without triggering the IRQ; -- * - IAAD potentially cleared without setting IAA. -- */ -- status = fotg210_readl(fotg210, &fotg210->regs->status); -- if ((status & STS_IAA) || !(cmd & CMD_IAAD)) { -- INCR(fotg210->stats.lost_iaa); -- fotg210_writel(fotg210, STS_IAA, -- &fotg210->regs->status); -- } -- -- fotg210_dbg(fotg210, "IAA watchdog: status %x cmd %x\n", -- status, cmd); -- end_unlink_async(fotg210); -- } --} -- -- --/* Enable the I/O watchdog, if appropriate */ --static void turn_on_io_watchdog(struct fotg210_hcd *fotg210) --{ -- /* Not needed if the controller isn't running or it's already enabled */ -- if (fotg210->rh_state != FOTG210_RH_RUNNING || -- (fotg210->enabled_hrtimer_events & -- BIT(FOTG210_HRTIMER_IO_WATCHDOG))) -- return; -- -- /* -- * Isochronous transfers always need the watchdog. -- * For other sorts we use it only if the flag is set. -- */ -- if (fotg210->isoc_count > 0 || (fotg210->need_io_watchdog && -- fotg210->async_count + fotg210->intr_count > 0)) -- fotg210_enable_event(fotg210, FOTG210_HRTIMER_IO_WATCHDOG, -- true); --} -- -- --/* Handler functions for the hrtimer event types. -- * Keep this array in the same order as the event types indexed by -- * enum fotg210_hrtimer_event in fotg210.h. -- */ --static void (*event_handlers[])(struct fotg210_hcd *) = { -- fotg210_poll_ASS, /* FOTG210_HRTIMER_POLL_ASS */ -- fotg210_poll_PSS, /* FOTG210_HRTIMER_POLL_PSS */ -- fotg210_handle_controller_death, /* FOTG210_HRTIMER_POLL_DEAD */ -- fotg210_handle_intr_unlinks, /* FOTG210_HRTIMER_UNLINK_INTR */ -- end_free_itds, /* FOTG210_HRTIMER_FREE_ITDS */ -- unlink_empty_async, /* FOTG210_HRTIMER_ASYNC_UNLINKS */ -- fotg210_iaa_watchdog, /* FOTG210_HRTIMER_IAA_WATCHDOG */ -- fotg210_disable_PSE, /* FOTG210_HRTIMER_DISABLE_PERIODIC */ -- fotg210_disable_ASE, /* FOTG210_HRTIMER_DISABLE_ASYNC */ -- fotg210_work, /* FOTG210_HRTIMER_IO_WATCHDOG */ --}; -- --static enum hrtimer_restart fotg210_hrtimer_func(struct hrtimer *t) --{ -- struct fotg210_hcd *fotg210 = -- container_of(t, struct fotg210_hcd, hrtimer); -- ktime_t now; -- unsigned long events; -- unsigned long flags; -- unsigned e; -- -- spin_lock_irqsave(&fotg210->lock, flags); -- -- events = fotg210->enabled_hrtimer_events; -- fotg210->enabled_hrtimer_events = 0; -- fotg210->next_hrtimer_event = FOTG210_HRTIMER_NO_EVENT; -- -- /* -- * Check each pending event. If its time has expired, handle -- * the event; otherwise re-enable it. -- */ -- now = ktime_get(); -- for_each_set_bit(e, &events, FOTG210_HRTIMER_NUM_EVENTS) { -- if (ktime_compare(now, fotg210->hr_timeouts[e]) >= 0) -- event_handlers[e](fotg210); -- else -- fotg210_enable_event(fotg210, e, false); -- } -- -- spin_unlock_irqrestore(&fotg210->lock, flags); -- return HRTIMER_NORESTART; --} -- --#define fotg210_bus_suspend NULL --#define fotg210_bus_resume NULL -- --static int check_reset_complete(struct fotg210_hcd *fotg210, int index, -- u32 __iomem *status_reg, int port_status) --{ -- if (!(port_status & PORT_CONNECT)) -- return port_status; -- -- /* if reset finished and it's still not enabled -- handoff */ -- if (!(port_status & PORT_PE)) -- /* with integrated TT, there's nobody to hand it to! */ -- fotg210_dbg(fotg210, "Failed to enable port %d on root hub TT\n", -- index + 1); -- else -- fotg210_dbg(fotg210, "port %d reset complete, port enabled\n", -- index + 1); -- -- return port_status; --} -- -- --/* build "status change" packet (one or two bytes) from HC registers */ -- --static int fotg210_hub_status_data(struct usb_hcd *hcd, char *buf) --{ -- struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); -- u32 temp, status; -- u32 mask; -- int retval = 1; -- unsigned long flags; -- -- /* init status to no-changes */ -- buf[0] = 0; -- -- /* Inform the core about resumes-in-progress by returning -- * a non-zero value even if there are no status changes. -- */ -- status = fotg210->resuming_ports; -- -- mask = PORT_CSC | PORT_PEC; -- /* PORT_RESUME from hardware ~= PORT_STAT_C_SUSPEND */ -- -- /* no hub change reports (bit 0) for now (power, ...) */ -- -- /* port N changes (bit N)? */ -- spin_lock_irqsave(&fotg210->lock, flags); -- -- temp = fotg210_readl(fotg210, &fotg210->regs->port_status); -- -- /* -- * Return status information even for ports with OWNER set. -- * Otherwise hub_wq wouldn't see the disconnect event when a -- * high-speed device is switched over to the companion -- * controller by the user. -- */ -- -- if ((temp & mask) != 0 || test_bit(0, &fotg210->port_c_suspend) || -- (fotg210->reset_done[0] && -- time_after_eq(jiffies, fotg210->reset_done[0]))) { -- buf[0] |= 1 << 1; -- status = STS_PCD; -- } -- /* FIXME autosuspend idle root hubs */ -- spin_unlock_irqrestore(&fotg210->lock, flags); -- return status ? retval : 0; --} -- --static void fotg210_hub_descriptor(struct fotg210_hcd *fotg210, -- struct usb_hub_descriptor *desc) --{ -- int ports = HCS_N_PORTS(fotg210->hcs_params); -- u16 temp; -- -- desc->bDescriptorType = USB_DT_HUB; -- desc->bPwrOn2PwrGood = 10; /* fotg210 1.0, 2.3.9 says 20ms max */ -- desc->bHubContrCurrent = 0; -- -- desc->bNbrPorts = ports; -- temp = 1 + (ports / 8); -- desc->bDescLength = 7 + 2 * temp; -- -- /* two bitmaps: ports removable, and usb 1.0 legacy PortPwrCtrlMask */ -- memset(&desc->u.hs.DeviceRemovable[0], 0, temp); -- memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp); -- -- temp = HUB_CHAR_INDV_PORT_OCPM; /* per-port overcurrent reporting */ -- temp |= HUB_CHAR_NO_LPSM; /* no power switching */ -- desc->wHubCharacteristics = cpu_to_le16(temp); --} -- --static int fotg210_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, -- u16 wIndex, char *buf, u16 wLength) --{ -- struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); -- int ports = HCS_N_PORTS(fotg210->hcs_params); -- u32 __iomem *status_reg = &fotg210->regs->port_status; -- u32 temp, temp1, status; -- unsigned long flags; -- int retval = 0; -- unsigned selector; -- -- /* -- * FIXME: support SetPortFeatures USB_PORT_FEAT_INDICATOR. -- * HCS_INDICATOR may say we can change LEDs to off/amber/green. -- * (track current state ourselves) ... blink for diagnostics, -- * power, "this is the one", etc. EHCI spec supports this. -- */ -- -- spin_lock_irqsave(&fotg210->lock, flags); -- switch (typeReq) { -- case ClearHubFeature: -- switch (wValue) { -- case C_HUB_LOCAL_POWER: -- case C_HUB_OVER_CURRENT: -- /* no hub-wide feature/status flags */ -- break; -- default: -- goto error; -- } -- break; -- case ClearPortFeature: -- if (!wIndex || wIndex > ports) -- goto error; -- wIndex--; -- temp = fotg210_readl(fotg210, status_reg); -- temp &= ~PORT_RWC_BITS; -- -- /* -- * Even if OWNER is set, so the port is owned by the -- * companion controller, hub_wq needs to be able to clear -- * the port-change status bits (especially -- * USB_PORT_STAT_C_CONNECTION). -- */ -- -- switch (wValue) { -- case USB_PORT_FEAT_ENABLE: -- fotg210_writel(fotg210, temp & ~PORT_PE, status_reg); -- break; -- case USB_PORT_FEAT_C_ENABLE: -- fotg210_writel(fotg210, temp | PORT_PEC, status_reg); -- break; -- case USB_PORT_FEAT_SUSPEND: -- if (temp & PORT_RESET) -- goto error; -- if (!(temp & PORT_SUSPEND)) -- break; -- if ((temp & PORT_PE) == 0) -- goto error; -- -- /* resume signaling for 20 msec */ -- fotg210_writel(fotg210, temp | PORT_RESUME, status_reg); -- fotg210->reset_done[wIndex] = jiffies -- + msecs_to_jiffies(USB_RESUME_TIMEOUT); -- break; -- case USB_PORT_FEAT_C_SUSPEND: -- clear_bit(wIndex, &fotg210->port_c_suspend); -- break; -- case USB_PORT_FEAT_C_CONNECTION: -- fotg210_writel(fotg210, temp | PORT_CSC, status_reg); -- break; -- case USB_PORT_FEAT_C_OVER_CURRENT: -- fotg210_writel(fotg210, temp | OTGISR_OVC, -- &fotg210->regs->otgisr); -- break; -- case USB_PORT_FEAT_C_RESET: -- /* GetPortStatus clears reset */ -- break; -- default: -- goto error; -- } -- fotg210_readl(fotg210, &fotg210->regs->command); -- break; -- case GetHubDescriptor: -- fotg210_hub_descriptor(fotg210, (struct usb_hub_descriptor *) -- buf); -- break; -- case GetHubStatus: -- /* no hub-wide feature/status flags */ -- memset(buf, 0, 4); -- /*cpu_to_le32s ((u32 *) buf); */ -- break; -- case GetPortStatus: -- if (!wIndex || wIndex > ports) -- goto error; -- wIndex--; -- status = 0; -- temp = fotg210_readl(fotg210, status_reg); -- -- /* wPortChange bits */ -- if (temp & PORT_CSC) -- status |= USB_PORT_STAT_C_CONNECTION << 16; -- if (temp & PORT_PEC) -- status |= USB_PORT_STAT_C_ENABLE << 16; -- -- temp1 = fotg210_readl(fotg210, &fotg210->regs->otgisr); -- if (temp1 & OTGISR_OVC) -- status |= USB_PORT_STAT_C_OVERCURRENT << 16; -- -- /* whoever resumes must GetPortStatus to complete it!! */ -- if (temp & PORT_RESUME) { -- -- /* Remote Wakeup received? */ -- if (!fotg210->reset_done[wIndex]) { -- /* resume signaling for 20 msec */ -- fotg210->reset_done[wIndex] = jiffies -- + msecs_to_jiffies(20); -- /* check the port again */ -- mod_timer(&fotg210_to_hcd(fotg210)->rh_timer, -- fotg210->reset_done[wIndex]); -- } -- -- /* resume completed? */ -- else if (time_after_eq(jiffies, -- fotg210->reset_done[wIndex])) { -- clear_bit(wIndex, &fotg210->suspended_ports); -- set_bit(wIndex, &fotg210->port_c_suspend); -- fotg210->reset_done[wIndex] = 0; -- -- /* stop resume signaling */ -- temp = fotg210_readl(fotg210, status_reg); -- fotg210_writel(fotg210, temp & -- ~(PORT_RWC_BITS | PORT_RESUME), -- status_reg); -- clear_bit(wIndex, &fotg210->resuming_ports); -- retval = handshake(fotg210, status_reg, -- PORT_RESUME, 0, 2000);/* 2ms */ -- if (retval != 0) { -- fotg210_err(fotg210, -- "port %d resume error %d\n", -- wIndex + 1, retval); -- goto error; -- } -- temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10)); -- } -- } -- -- /* whoever resets must GetPortStatus to complete it!! */ -- if ((temp & PORT_RESET) && time_after_eq(jiffies, -- fotg210->reset_done[wIndex])) { -- status |= USB_PORT_STAT_C_RESET << 16; -- fotg210->reset_done[wIndex] = 0; -- clear_bit(wIndex, &fotg210->resuming_ports); -- -- /* force reset to complete */ -- fotg210_writel(fotg210, -- temp & ~(PORT_RWC_BITS | PORT_RESET), -- status_reg); -- /* REVISIT: some hardware needs 550+ usec to clear -- * this bit; seems too long to spin routinely... -- */ -- retval = handshake(fotg210, status_reg, -- PORT_RESET, 0, 1000); -- if (retval != 0) { -- fotg210_err(fotg210, "port %d reset error %d\n", -- wIndex + 1, retval); -- goto error; -- } -- -- /* see what we found out */ -- temp = check_reset_complete(fotg210, wIndex, status_reg, -- fotg210_readl(fotg210, status_reg)); -- -- /* restart schedule */ -- fotg210->command |= CMD_RUN; -- fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command); -- } -- -- if (!(temp & (PORT_RESUME|PORT_RESET))) { -- fotg210->reset_done[wIndex] = 0; -- clear_bit(wIndex, &fotg210->resuming_ports); -- } -- -- /* transfer dedicated ports to the companion hc */ -- if ((temp & PORT_CONNECT) && -- test_bit(wIndex, &fotg210->companion_ports)) { -- temp &= ~PORT_RWC_BITS; -- fotg210_writel(fotg210, temp, status_reg); -- fotg210_dbg(fotg210, "port %d --> companion\n", -- wIndex + 1); -- temp = fotg210_readl(fotg210, status_reg); -- } -- -- /* -- * Even if OWNER is set, there's no harm letting hub_wq -- * see the wPortStatus values (they should all be 0 except -- * for PORT_POWER anyway). -- */ -- -- if (temp & PORT_CONNECT) { -- status |= USB_PORT_STAT_CONNECTION; -- status |= fotg210_port_speed(fotg210, temp); -- } -- if (temp & PORT_PE) -- status |= USB_PORT_STAT_ENABLE; -- -- /* maybe the port was unsuspended without our knowledge */ -- if (temp & (PORT_SUSPEND|PORT_RESUME)) { -- status |= USB_PORT_STAT_SUSPEND; -- } else if (test_bit(wIndex, &fotg210->suspended_ports)) { -- clear_bit(wIndex, &fotg210->suspended_ports); -- clear_bit(wIndex, &fotg210->resuming_ports); -- fotg210->reset_done[wIndex] = 0; -- if (temp & PORT_PE) -- set_bit(wIndex, &fotg210->port_c_suspend); -- } -- -- temp1 = fotg210_readl(fotg210, &fotg210->regs->otgisr); -- if (temp1 & OTGISR_OVC) -- status |= USB_PORT_STAT_OVERCURRENT; -- if (temp & PORT_RESET) -- status |= USB_PORT_STAT_RESET; -- if (test_bit(wIndex, &fotg210->port_c_suspend)) -- status |= USB_PORT_STAT_C_SUSPEND << 16; -- -- if (status & ~0xffff) /* only if wPortChange is interesting */ -- dbg_port(fotg210, "GetStatus", wIndex + 1, temp); -- put_unaligned_le32(status, buf); -- break; -- case SetHubFeature: -- switch (wValue) { -- case C_HUB_LOCAL_POWER: -- case C_HUB_OVER_CURRENT: -- /* no hub-wide feature/status flags */ -- break; -- default: -- goto error; -- } -- break; -- case SetPortFeature: -- selector = wIndex >> 8; -- wIndex &= 0xff; -- -- if (!wIndex || wIndex > ports) -- goto error; -- wIndex--; -- temp = fotg210_readl(fotg210, status_reg); -- temp &= ~PORT_RWC_BITS; -- switch (wValue) { -- case USB_PORT_FEAT_SUSPEND: -- if ((temp & PORT_PE) == 0 -- || (temp & PORT_RESET) != 0) -- goto error; -- -- /* After above check the port must be connected. -- * Set appropriate bit thus could put phy into low power -- * mode if we have hostpc feature -- */ -- fotg210_writel(fotg210, temp | PORT_SUSPEND, -- status_reg); -- set_bit(wIndex, &fotg210->suspended_ports); -- break; -- case USB_PORT_FEAT_RESET: -- if (temp & PORT_RESUME) -- goto error; -- /* line status bits may report this as low speed, -- * which can be fine if this root hub has a -- * transaction translator built in. -- */ -- fotg210_dbg(fotg210, "port %d reset\n", wIndex + 1); -- temp |= PORT_RESET; -- temp &= ~PORT_PE; -- -- /* -- * caller must wait, then call GetPortStatus -- * usb 2.0 spec says 50 ms resets on root -- */ -- fotg210->reset_done[wIndex] = jiffies -- + msecs_to_jiffies(50); -- fotg210_writel(fotg210, temp, status_reg); -- break; -- -- /* For downstream facing ports (these): one hub port is put -- * into test mode according to USB2 11.24.2.13, then the hub -- * must be reset (which for root hub now means rmmod+modprobe, -- * or else system reboot). See EHCI 2.3.9 and 4.14 for info -- * about the EHCI-specific stuff. -- */ -- case USB_PORT_FEAT_TEST: -- if (!selector || selector > 5) -- goto error; -- spin_unlock_irqrestore(&fotg210->lock, flags); -- fotg210_quiesce(fotg210); -- spin_lock_irqsave(&fotg210->lock, flags); -- -- /* Put all enabled ports into suspend */ -- temp = fotg210_readl(fotg210, status_reg) & -- ~PORT_RWC_BITS; -- if (temp & PORT_PE) -- fotg210_writel(fotg210, temp | PORT_SUSPEND, -- status_reg); -- -- spin_unlock_irqrestore(&fotg210->lock, flags); -- fotg210_halt(fotg210); -- spin_lock_irqsave(&fotg210->lock, flags); -- -- temp = fotg210_readl(fotg210, status_reg); -- temp |= selector << 16; -- fotg210_writel(fotg210, temp, status_reg); -- break; -- -- default: -- goto error; -- } -- fotg210_readl(fotg210, &fotg210->regs->command); -- break; -- -- default: --error: -- /* "stall" on error */ -- retval = -EPIPE; -- } -- spin_unlock_irqrestore(&fotg210->lock, flags); -- return retval; --} -- --static void __maybe_unused fotg210_relinquish_port(struct usb_hcd *hcd, -- int portnum) --{ -- return; --} -- --static int __maybe_unused fotg210_port_handed_over(struct usb_hcd *hcd, -- int portnum) --{ -- return 0; --} -- --/* There's basically three types of memory: -- * - data used only by the HCD ... kmalloc is fine -- * - async and periodic schedules, shared by HC and HCD ... these -- * need to use dma_pool or dma_alloc_coherent -- * - driver buffers, read/written by HC ... single shot DMA mapped -- * -- * There's also "register" data (e.g. PCI or SOC), which is memory mapped. -- * No memory seen by this driver is pageable. -- */ -- --/* Allocate the key transfer structures from the previously allocated pool */ --static inline void fotg210_qtd_init(struct fotg210_hcd *fotg210, -- struct fotg210_qtd *qtd, dma_addr_t dma) --{ -- memset(qtd, 0, sizeof(*qtd)); -- qtd->qtd_dma = dma; -- qtd->hw_token = cpu_to_hc32(fotg210, QTD_STS_HALT); -- qtd->hw_next = FOTG210_LIST_END(fotg210); -- qtd->hw_alt_next = FOTG210_LIST_END(fotg210); -- INIT_LIST_HEAD(&qtd->qtd_list); --} -- --static struct fotg210_qtd *fotg210_qtd_alloc(struct fotg210_hcd *fotg210, -- gfp_t flags) --{ -- struct fotg210_qtd *qtd; -- dma_addr_t dma; -- -- qtd = dma_pool_alloc(fotg210->qtd_pool, flags, &dma); -- if (qtd != NULL) -- fotg210_qtd_init(fotg210, qtd, dma); -- -- return qtd; --} -- --static inline void fotg210_qtd_free(struct fotg210_hcd *fotg210, -- struct fotg210_qtd *qtd) --{ -- dma_pool_free(fotg210->qtd_pool, qtd, qtd->qtd_dma); --} -- -- --static void qh_destroy(struct fotg210_hcd *fotg210, struct fotg210_qh *qh) --{ -- /* clean qtds first, and know this is not linked */ -- if (!list_empty(&qh->qtd_list) || qh->qh_next.ptr) { -- fotg210_dbg(fotg210, "unused qh not empty!\n"); -- BUG(); -- } -- if (qh->dummy) -- fotg210_qtd_free(fotg210, qh->dummy); -- dma_pool_free(fotg210->qh_pool, qh->hw, qh->qh_dma); -- kfree(qh); --} -- --static struct fotg210_qh *fotg210_qh_alloc(struct fotg210_hcd *fotg210, -- gfp_t flags) --{ -- struct fotg210_qh *qh; -- dma_addr_t dma; -- -- qh = kzalloc(sizeof(*qh), GFP_ATOMIC); -- if (!qh) -- goto done; -- qh->hw = (struct fotg210_qh_hw *) -- dma_pool_zalloc(fotg210->qh_pool, flags, &dma); -- if (!qh->hw) -- goto fail; -- qh->qh_dma = dma; -- INIT_LIST_HEAD(&qh->qtd_list); -- -- /* dummy td enables safe urb queuing */ -- qh->dummy = fotg210_qtd_alloc(fotg210, flags); -- if (qh->dummy == NULL) { -- fotg210_dbg(fotg210, "no dummy td\n"); -- goto fail1; -- } --done: -- return qh; --fail1: -- dma_pool_free(fotg210->qh_pool, qh->hw, qh->qh_dma); --fail: -- kfree(qh); -- return NULL; --} -- --/* The queue heads and transfer descriptors are managed from pools tied -- * to each of the "per device" structures. -- * This is the initialisation and cleanup code. -- */ -- --static void fotg210_mem_cleanup(struct fotg210_hcd *fotg210) --{ -- if (fotg210->async) -- qh_destroy(fotg210, fotg210->async); -- fotg210->async = NULL; -- -- if (fotg210->dummy) -- qh_destroy(fotg210, fotg210->dummy); -- fotg210->dummy = NULL; -- -- /* DMA consistent memory and pools */ -- dma_pool_destroy(fotg210->qtd_pool); -- fotg210->qtd_pool = NULL; -- -- dma_pool_destroy(fotg210->qh_pool); -- fotg210->qh_pool = NULL; -- -- dma_pool_destroy(fotg210->itd_pool); -- fotg210->itd_pool = NULL; -- -- if (fotg210->periodic) -- dma_free_coherent(fotg210_to_hcd(fotg210)->self.controller, -- fotg210->periodic_size * sizeof(u32), -- fotg210->periodic, fotg210->periodic_dma); -- fotg210->periodic = NULL; -- -- /* shadow periodic table */ -- kfree(fotg210->pshadow); -- fotg210->pshadow = NULL; --} -- --/* remember to add cleanup code (above) if you add anything here */ --static int fotg210_mem_init(struct fotg210_hcd *fotg210, gfp_t flags) --{ -- int i; -- -- /* QTDs for control/bulk/intr transfers */ -- fotg210->qtd_pool = dma_pool_create("fotg210_qtd", -- fotg210_to_hcd(fotg210)->self.controller, -- sizeof(struct fotg210_qtd), -- 32 /* byte alignment (for hw parts) */, -- 4096 /* can't cross 4K */); -- if (!fotg210->qtd_pool) -- goto fail; -- -- /* QHs for control/bulk/intr transfers */ -- fotg210->qh_pool = dma_pool_create("fotg210_qh", -- fotg210_to_hcd(fotg210)->self.controller, -- sizeof(struct fotg210_qh_hw), -- 32 /* byte alignment (for hw parts) */, -- 4096 /* can't cross 4K */); -- if (!fotg210->qh_pool) -- goto fail; -- -- fotg210->async = fotg210_qh_alloc(fotg210, flags); -- if (!fotg210->async) -- goto fail; -- -- /* ITD for high speed ISO transfers */ -- fotg210->itd_pool = dma_pool_create("fotg210_itd", -- fotg210_to_hcd(fotg210)->self.controller, -- sizeof(struct fotg210_itd), -- 64 /* byte alignment (for hw parts) */, -- 4096 /* can't cross 4K */); -- if (!fotg210->itd_pool) -- goto fail; -- -- /* Hardware periodic table */ -- fotg210->periodic = -- dma_alloc_coherent(fotg210_to_hcd(fotg210)->self.controller, -- fotg210->periodic_size * sizeof(__le32), -- &fotg210->periodic_dma, 0); -- if (fotg210->periodic == NULL) -- goto fail; -- -- for (i = 0; i < fotg210->periodic_size; i++) -- fotg210->periodic[i] = FOTG210_LIST_END(fotg210); -- -- /* software shadow of hardware table */ -- fotg210->pshadow = kcalloc(fotg210->periodic_size, sizeof(void *), -- flags); -- if (fotg210->pshadow != NULL) -- return 0; -- --fail: -- fotg210_dbg(fotg210, "couldn't init memory\n"); -- fotg210_mem_cleanup(fotg210); -- return -ENOMEM; --} --/* EHCI hardware queue manipulation ... the core. QH/QTD manipulation. -- * -- * Control, bulk, and interrupt traffic all use "qh" lists. They list "qtd" -- * entries describing USB transactions, max 16-20kB/entry (with 4kB-aligned -- * buffers needed for the larger number). We use one QH per endpoint, queue -- * multiple urbs (all three types) per endpoint. URBs may need several qtds. -- * -- * ISO traffic uses "ISO TD" (itd) records, and (along with -- * interrupts) needs careful scheduling. Performance improvements can be -- * an ongoing challenge. That's in "ehci-sched.c". -- * -- * USB 1.1 devices are handled (a) by "companion" OHCI or UHCI root hubs, -- * or otherwise through transaction translators (TTs) in USB 2.0 hubs using -- * (b) special fields in qh entries or (c) split iso entries. TTs will -- * buffer low/full speed data so the host collects it at high speed. -- */ -- --/* fill a qtd, returning how much of the buffer we were able to queue up */ --static int qtd_fill(struct fotg210_hcd *fotg210, struct fotg210_qtd *qtd, -- dma_addr_t buf, size_t len, int token, int maxpacket) --{ -- int i, count; -- u64 addr = buf; -- -- /* one buffer entry per 4K ... first might be short or unaligned */ -- qtd->hw_buf[0] = cpu_to_hc32(fotg210, (u32)addr); -- qtd->hw_buf_hi[0] = cpu_to_hc32(fotg210, (u32)(addr >> 32)); -- count = 0x1000 - (buf & 0x0fff); /* rest of that page */ -- if (likely(len < count)) /* ... iff needed */ -- count = len; -- else { -- buf += 0x1000; -- buf &= ~0x0fff; -- -- /* per-qtd limit: from 16K to 20K (best alignment) */ -- for (i = 1; count < len && i < 5; i++) { -- addr = buf; -- qtd->hw_buf[i] = cpu_to_hc32(fotg210, (u32)addr); -- qtd->hw_buf_hi[i] = cpu_to_hc32(fotg210, -- (u32)(addr >> 32)); -- buf += 0x1000; -- if ((count + 0x1000) < len) -- count += 0x1000; -- else -- count = len; -- } -- -- /* short packets may only terminate transfers */ -- if (count != len) -- count -= (count % maxpacket); -- } -- qtd->hw_token = cpu_to_hc32(fotg210, (count << 16) | token); -- qtd->length = count; -- -- return count; --} -- --static inline void qh_update(struct fotg210_hcd *fotg210, -- struct fotg210_qh *qh, struct fotg210_qtd *qtd) --{ -- struct fotg210_qh_hw *hw = qh->hw; -- -- /* writes to an active overlay are unsafe */ -- BUG_ON(qh->qh_state != QH_STATE_IDLE); -- -- hw->hw_qtd_next = QTD_NEXT(fotg210, qtd->qtd_dma); -- hw->hw_alt_next = FOTG210_LIST_END(fotg210); -- -- /* Except for control endpoints, we make hardware maintain data -- * toggle (like OHCI) ... here (re)initialize the toggle in the QH, -- * and set the pseudo-toggle in udev. Only usb_clear_halt() will -- * ever clear it. -- */ -- if (!(hw->hw_info1 & cpu_to_hc32(fotg210, QH_TOGGLE_CTL))) { -- unsigned is_out, epnum; -- -- is_out = qh->is_out; -- epnum = (hc32_to_cpup(fotg210, &hw->hw_info1) >> 8) & 0x0f; -- if (unlikely(!usb_gettoggle(qh->dev, epnum, is_out))) { -- hw->hw_token &= ~cpu_to_hc32(fotg210, QTD_TOGGLE); -- usb_settoggle(qh->dev, epnum, is_out, 1); -- } -- } -- -- hw->hw_token &= cpu_to_hc32(fotg210, QTD_TOGGLE | QTD_STS_PING); --} -- --/* if it weren't for a common silicon quirk (writing the dummy into the qh -- * overlay, so qh->hw_token wrongly becomes inactive/halted), only fault -- * recovery (including urb dequeue) would need software changes to a QH... -- */ --static void qh_refresh(struct fotg210_hcd *fotg210, struct fotg210_qh *qh) --{ -- struct fotg210_qtd *qtd; -- -- if (list_empty(&qh->qtd_list)) -- qtd = qh->dummy; -- else { -- qtd = list_entry(qh->qtd_list.next, -- struct fotg210_qtd, qtd_list); -- /* -- * first qtd may already be partially processed. -- * If we come here during unlink, the QH overlay region -- * might have reference to the just unlinked qtd. The -- * qtd is updated in qh_completions(). Update the QH -- * overlay here. -- */ -- if (cpu_to_hc32(fotg210, qtd->qtd_dma) == qh->hw->hw_current) { -- qh->hw->hw_qtd_next = qtd->hw_next; -- qtd = NULL; -- } -- } -- -- if (qtd) -- qh_update(fotg210, qh, qtd); --} -- --static void qh_link_async(struct fotg210_hcd *fotg210, struct fotg210_qh *qh); -- --static void fotg210_clear_tt_buffer_complete(struct usb_hcd *hcd, -- struct usb_host_endpoint *ep) --{ -- struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); -- struct fotg210_qh *qh = ep->hcpriv; -- unsigned long flags; -- -- spin_lock_irqsave(&fotg210->lock, flags); -- qh->clearing_tt = 0; -- if (qh->qh_state == QH_STATE_IDLE && !list_empty(&qh->qtd_list) -- && fotg210->rh_state == FOTG210_RH_RUNNING) -- qh_link_async(fotg210, qh); -- spin_unlock_irqrestore(&fotg210->lock, flags); --} -- --static void fotg210_clear_tt_buffer(struct fotg210_hcd *fotg210, -- struct fotg210_qh *qh, struct urb *urb, u32 token) --{ -- -- /* If an async split transaction gets an error or is unlinked, -- * the TT buffer may be left in an indeterminate state. We -- * have to clear the TT buffer. -- * -- * Note: this routine is never called for Isochronous transfers. -- */ -- if (urb->dev->tt && !usb_pipeint(urb->pipe) && !qh->clearing_tt) { -- struct usb_device *tt = urb->dev->tt->hub; -- -- dev_dbg(&tt->dev, -- "clear tt buffer port %d, a%d ep%d t%08x\n", -- urb->dev->ttport, urb->dev->devnum, -- usb_pipeendpoint(urb->pipe), token); -- -- if (urb->dev->tt->hub != -- fotg210_to_hcd(fotg210)->self.root_hub) { -- if (usb_hub_clear_tt_buffer(urb) == 0) -- qh->clearing_tt = 1; -- } -- } --} -- --static int qtd_copy_status(struct fotg210_hcd *fotg210, struct urb *urb, -- size_t length, u32 token) --{ -- int status = -EINPROGRESS; -- -- /* count IN/OUT bytes, not SETUP (even short packets) */ -- if (likely(QTD_PID(token) != 2)) -- urb->actual_length += length - QTD_LENGTH(token); -- -- /* don't modify error codes */ -- if (unlikely(urb->unlinked)) -- return status; -- -- /* force cleanup after short read; not always an error */ -- if (unlikely(IS_SHORT_READ(token))) -- status = -EREMOTEIO; -- -- /* serious "can't proceed" faults reported by the hardware */ -- if (token & QTD_STS_HALT) { -- if (token & QTD_STS_BABBLE) { -- /* FIXME "must" disable babbling device's port too */ -- status = -EOVERFLOW; -- /* CERR nonzero + halt --> stall */ -- } else if (QTD_CERR(token)) { -- status = -EPIPE; -- -- /* In theory, more than one of the following bits can be set -- * since they are sticky and the transaction is retried. -- * Which to test first is rather arbitrary. -- */ -- } else if (token & QTD_STS_MMF) { -- /* fs/ls interrupt xfer missed the complete-split */ -- status = -EPROTO; -- } else if (token & QTD_STS_DBE) { -- status = (QTD_PID(token) == 1) /* IN ? */ -- ? -ENOSR /* hc couldn't read data */ -- : -ECOMM; /* hc couldn't write data */ -- } else if (token & QTD_STS_XACT) { -- /* timeout, bad CRC, wrong PID, etc */ -- fotg210_dbg(fotg210, "devpath %s ep%d%s 3strikes\n", -- urb->dev->devpath, -- usb_pipeendpoint(urb->pipe), -- usb_pipein(urb->pipe) ? "in" : "out"); -- status = -EPROTO; -- } else { /* unknown */ -- status = -EPROTO; -- } -- -- fotg210_dbg(fotg210, -- "dev%d ep%d%s qtd token %08x --> status %d\n", -- usb_pipedevice(urb->pipe), -- usb_pipeendpoint(urb->pipe), -- usb_pipein(urb->pipe) ? "in" : "out", -- token, status); -- } -- -- return status; --} -- --static void fotg210_urb_done(struct fotg210_hcd *fotg210, struct urb *urb, -- int status) --__releases(fotg210->lock) --__acquires(fotg210->lock) --{ -- if (likely(urb->hcpriv != NULL)) { -- struct fotg210_qh *qh = (struct fotg210_qh *) urb->hcpriv; -- -- /* S-mask in a QH means it's an interrupt urb */ -- if ((qh->hw->hw_info2 & cpu_to_hc32(fotg210, QH_SMASK)) != 0) { -- -- /* ... update hc-wide periodic stats (for usbfs) */ -- fotg210_to_hcd(fotg210)->self.bandwidth_int_reqs--; -- } -- } -- -- if (unlikely(urb->unlinked)) { -- INCR(fotg210->stats.unlink); -- } else { -- /* report non-error and short read status as zero */ -- if (status == -EINPROGRESS || status == -EREMOTEIO) -- status = 0; -- INCR(fotg210->stats.complete); -- } -- --#ifdef FOTG210_URB_TRACE -- fotg210_dbg(fotg210, -- "%s %s urb %p ep%d%s status %d len %d/%d\n", -- __func__, urb->dev->devpath, urb, -- usb_pipeendpoint(urb->pipe), -- usb_pipein(urb->pipe) ? "in" : "out", -- status, -- urb->actual_length, urb->transfer_buffer_length); --#endif -- -- /* complete() can reenter this HCD */ -- usb_hcd_unlink_urb_from_ep(fotg210_to_hcd(fotg210), urb); -- spin_unlock(&fotg210->lock); -- usb_hcd_giveback_urb(fotg210_to_hcd(fotg210), urb, status); -- spin_lock(&fotg210->lock); --} -- --static int qh_schedule(struct fotg210_hcd *fotg210, struct fotg210_qh *qh); -- --/* Process and free completed qtds for a qh, returning URBs to drivers. -- * Chases up to qh->hw_current. Returns number of completions called, -- * indicating how much "real" work we did. -- */ --static unsigned qh_completions(struct fotg210_hcd *fotg210, -- struct fotg210_qh *qh) --{ -- struct fotg210_qtd *last, *end = qh->dummy; -- struct fotg210_qtd *qtd, *tmp; -- int last_status; -- int stopped; -- unsigned count = 0; -- u8 state; -- struct fotg210_qh_hw *hw = qh->hw; -- -- if (unlikely(list_empty(&qh->qtd_list))) -- return count; -- -- /* completions (or tasks on other cpus) must never clobber HALT -- * till we've gone through and cleaned everything up, even when -- * they add urbs to this qh's queue or mark them for unlinking. -- * -- * NOTE: unlinking expects to be done in queue order. -- * -- * It's a bug for qh->qh_state to be anything other than -- * QH_STATE_IDLE, unless our caller is scan_async() or -- * scan_intr(). -- */ -- state = qh->qh_state; -- qh->qh_state = QH_STATE_COMPLETING; -- stopped = (state == QH_STATE_IDLE); -- --rescan: -- last = NULL; -- last_status = -EINPROGRESS; -- qh->needs_rescan = 0; -- -- /* remove de-activated QTDs from front of queue. -- * after faults (including short reads), cleanup this urb -- * then let the queue advance. -- * if queue is stopped, handles unlinks. -- */ -- list_for_each_entry_safe(qtd, tmp, &qh->qtd_list, qtd_list) { -- struct urb *urb; -- u32 token = 0; -- -- urb = qtd->urb; -- -- /* clean up any state from previous QTD ...*/ -- if (last) { -- if (likely(last->urb != urb)) { -- fotg210_urb_done(fotg210, last->urb, -- last_status); -- count++; -- last_status = -EINPROGRESS; -- } -- fotg210_qtd_free(fotg210, last); -- last = NULL; -- } -- -- /* ignore urbs submitted during completions we reported */ -- if (qtd == end) -- break; -- -- /* hardware copies qtd out of qh overlay */ -- rmb(); -- token = hc32_to_cpu(fotg210, qtd->hw_token); -- -- /* always clean up qtds the hc de-activated */ --retry_xacterr: -- if ((token & QTD_STS_ACTIVE) == 0) { -- -- /* Report Data Buffer Error: non-fatal but useful */ -- if (token & QTD_STS_DBE) -- fotg210_dbg(fotg210, -- "detected DataBufferErr for urb %p ep%d%s len %d, qtd %p [qh %p]\n", -- urb, usb_endpoint_num(&urb->ep->desc), -- usb_endpoint_dir_in(&urb->ep->desc) -- ? "in" : "out", -- urb->transfer_buffer_length, qtd, qh); -- -- /* on STALL, error, and short reads this urb must -- * complete and all its qtds must be recycled. -- */ -- if ((token & QTD_STS_HALT) != 0) { -- -- /* retry transaction errors until we -- * reach the software xacterr limit -- */ -- if ((token & QTD_STS_XACT) && -- QTD_CERR(token) == 0 && -- ++qh->xacterrs < QH_XACTERR_MAX && -- !urb->unlinked) { -- fotg210_dbg(fotg210, -- "detected XactErr len %zu/%zu retry %d\n", -- qtd->length - QTD_LENGTH(token), -- qtd->length, -- qh->xacterrs); -- -- /* reset the token in the qtd and the -- * qh overlay (which still contains -- * the qtd) so that we pick up from -- * where we left off -- */ -- token &= ~QTD_STS_HALT; -- token |= QTD_STS_ACTIVE | -- (FOTG210_TUNE_CERR << 10); -- qtd->hw_token = cpu_to_hc32(fotg210, -- token); -- wmb(); -- hw->hw_token = cpu_to_hc32(fotg210, -- token); -- goto retry_xacterr; -- } -- stopped = 1; -- -- /* magic dummy for some short reads; qh won't advance. -- * that silicon quirk can kick in with this dummy too. -- * -- * other short reads won't stop the queue, including -- * control transfers (status stage handles that) or -- * most other single-qtd reads ... the queue stops if -- * URB_SHORT_NOT_OK was set so the driver submitting -- * the urbs could clean it up. -- */ -- } else if (IS_SHORT_READ(token) && -- !(qtd->hw_alt_next & -- FOTG210_LIST_END(fotg210))) { -- stopped = 1; -- } -- -- /* stop scanning when we reach qtds the hc is using */ -- } else if (likely(!stopped -- && fotg210->rh_state >= FOTG210_RH_RUNNING)) { -- break; -- -- /* scan the whole queue for unlinks whenever it stops */ -- } else { -- stopped = 1; -- -- /* cancel everything if we halt, suspend, etc */ -- if (fotg210->rh_state < FOTG210_RH_RUNNING) -- last_status = -ESHUTDOWN; -- -- /* this qtd is active; skip it unless a previous qtd -- * for its urb faulted, or its urb was canceled. -- */ -- else if (last_status == -EINPROGRESS && !urb->unlinked) -- continue; -- -- /* qh unlinked; token in overlay may be most current */ -- if (state == QH_STATE_IDLE && -- cpu_to_hc32(fotg210, qtd->qtd_dma) -- == hw->hw_current) { -- token = hc32_to_cpu(fotg210, hw->hw_token); -- -- /* An unlink may leave an incomplete -- * async transaction in the TT buffer. -- * We have to clear it. -- */ -- fotg210_clear_tt_buffer(fotg210, qh, urb, -- token); -- } -- } -- -- /* unless we already know the urb's status, collect qtd status -- * and update count of bytes transferred. in common short read -- * cases with only one data qtd (including control transfers), -- * queue processing won't halt. but with two or more qtds (for -- * example, with a 32 KB transfer), when the first qtd gets a -- * short read the second must be removed by hand. -- */ -- if (last_status == -EINPROGRESS) { -- last_status = qtd_copy_status(fotg210, urb, -- qtd->length, token); -- if (last_status == -EREMOTEIO && -- (qtd->hw_alt_next & -- FOTG210_LIST_END(fotg210))) -- last_status = -EINPROGRESS; -- -- /* As part of low/full-speed endpoint-halt processing -- * we must clear the TT buffer (11.17.5). -- */ -- if (unlikely(last_status != -EINPROGRESS && -- last_status != -EREMOTEIO)) { -- /* The TT's in some hubs malfunction when they -- * receive this request following a STALL (they -- * stop sending isochronous packets). Since a -- * STALL can't leave the TT buffer in a busy -- * state (if you believe Figures 11-48 - 11-51 -- * in the USB 2.0 spec), we won't clear the TT -- * buffer in this case. Strictly speaking this -- * is a violation of the spec. -- */ -- if (last_status != -EPIPE) -- fotg210_clear_tt_buffer(fotg210, qh, -- urb, token); -- } -- } -- -- /* if we're removing something not at the queue head, -- * patch the hardware queue pointer. -- */ -- if (stopped && qtd->qtd_list.prev != &qh->qtd_list) { -- last = list_entry(qtd->qtd_list.prev, -- struct fotg210_qtd, qtd_list); -- last->hw_next = qtd->hw_next; -- } -- -- /* remove qtd; it's recycled after possible urb completion */ -- list_del(&qtd->qtd_list); -- last = qtd; -- -- /* reinit the xacterr counter for the next qtd */ -- qh->xacterrs = 0; -- } -- -- /* last urb's completion might still need calling */ -- if (likely(last != NULL)) { -- fotg210_urb_done(fotg210, last->urb, last_status); -- count++; -- fotg210_qtd_free(fotg210, last); -- } -- -- /* Do we need to rescan for URBs dequeued during a giveback? */ -- if (unlikely(qh->needs_rescan)) { -- /* If the QH is already unlinked, do the rescan now. */ -- if (state == QH_STATE_IDLE) -- goto rescan; -- -- /* Otherwise we have to wait until the QH is fully unlinked. -- * Our caller will start an unlink if qh->needs_rescan is -- * set. But if an unlink has already started, nothing needs -- * to be done. -- */ -- if (state != QH_STATE_LINKED) -- qh->needs_rescan = 0; -- } -- -- /* restore original state; caller must unlink or relink */ -- qh->qh_state = state; -- -- /* be sure the hardware's done with the qh before refreshing -- * it after fault cleanup, or recovering from silicon wrongly -- * overlaying the dummy qtd (which reduces DMA chatter). -- */ -- if (stopped != 0 || hw->hw_qtd_next == FOTG210_LIST_END(fotg210)) { -- switch (state) { -- case QH_STATE_IDLE: -- qh_refresh(fotg210, qh); -- break; -- case QH_STATE_LINKED: -- /* We won't refresh a QH that's linked (after the HC -- * stopped the queue). That avoids a race: -- * - HC reads first part of QH; -- * - CPU updates that first part and the token; -- * - HC reads rest of that QH, including token -- * Result: HC gets an inconsistent image, and then -- * DMAs to/from the wrong memory (corrupting it). -- * -- * That should be rare for interrupt transfers, -- * except maybe high bandwidth ... -- */ -- -- /* Tell the caller to start an unlink */ -- qh->needs_rescan = 1; -- break; -- /* otherwise, unlink already started */ -- } -- } -- -- return count; --} -- --/* reverse of qh_urb_transaction: free a list of TDs. -- * used for cleanup after errors, before HC sees an URB's TDs. -- */ --static void qtd_list_free(struct fotg210_hcd *fotg210, struct urb *urb, -- struct list_head *head) --{ -- struct fotg210_qtd *qtd, *temp; -- -- list_for_each_entry_safe(qtd, temp, head, qtd_list) { -- list_del(&qtd->qtd_list); -- fotg210_qtd_free(fotg210, qtd); -- } --} -- --/* create a list of filled qtds for this URB; won't link into qh. -- */ --static struct list_head *qh_urb_transaction(struct fotg210_hcd *fotg210, -- struct urb *urb, struct list_head *head, gfp_t flags) --{ -- struct fotg210_qtd *qtd, *qtd_prev; -- dma_addr_t buf; -- int len, this_sg_len, maxpacket; -- int is_input; -- u32 token; -- int i; -- struct scatterlist *sg; -- -- /* -- * URBs map to sequences of QTDs: one logical transaction -- */ -- qtd = fotg210_qtd_alloc(fotg210, flags); -- if (unlikely(!qtd)) -- return NULL; -- list_add_tail(&qtd->qtd_list, head); -- qtd->urb = urb; -- -- token = QTD_STS_ACTIVE; -- token |= (FOTG210_TUNE_CERR << 10); -- /* for split transactions, SplitXState initialized to zero */ -- -- len = urb->transfer_buffer_length; -- is_input = usb_pipein(urb->pipe); -- if (usb_pipecontrol(urb->pipe)) { -- /* SETUP pid */ -- qtd_fill(fotg210, qtd, urb->setup_dma, -- sizeof(struct usb_ctrlrequest), -- token | (2 /* "setup" */ << 8), 8); -- -- /* ... and always at least one more pid */ -- token ^= QTD_TOGGLE; -- qtd_prev = qtd; -- qtd = fotg210_qtd_alloc(fotg210, flags); -- if (unlikely(!qtd)) -- goto cleanup; -- qtd->urb = urb; -- qtd_prev->hw_next = QTD_NEXT(fotg210, qtd->qtd_dma); -- list_add_tail(&qtd->qtd_list, head); -- -- /* for zero length DATA stages, STATUS is always IN */ -- if (len == 0) -- token |= (1 /* "in" */ << 8); -- } -- -- /* -- * data transfer stage: buffer setup -- */ -- i = urb->num_mapped_sgs; -- if (len > 0 && i > 0) { -- sg = urb->sg; -- buf = sg_dma_address(sg); -- -- /* urb->transfer_buffer_length may be smaller than the -- * size of the scatterlist (or vice versa) -- */ -- this_sg_len = min_t(int, sg_dma_len(sg), len); -- } else { -- sg = NULL; -- buf = urb->transfer_dma; -- this_sg_len = len; -- } -- -- if (is_input) -- token |= (1 /* "in" */ << 8); -- /* else it's already initted to "out" pid (0 << 8) */ -- -- maxpacket = usb_maxpacket(urb->dev, urb->pipe); -- -- /* -- * buffer gets wrapped in one or more qtds; -- * last one may be "short" (including zero len) -- * and may serve as a control status ack -- */ -- for (;;) { -- int this_qtd_len; -- -- this_qtd_len = qtd_fill(fotg210, qtd, buf, this_sg_len, token, -- maxpacket); -- this_sg_len -= this_qtd_len; -- len -= this_qtd_len; -- buf += this_qtd_len; -- -- /* -- * short reads advance to a "magic" dummy instead of the next -- * qtd ... that forces the queue to stop, for manual cleanup. -- * (this will usually be overridden later.) -- */ -- if (is_input) -- qtd->hw_alt_next = fotg210->async->hw->hw_alt_next; -- -- /* qh makes control packets use qtd toggle; maybe switch it */ -- if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0) -- token ^= QTD_TOGGLE; -- -- if (likely(this_sg_len <= 0)) { -- if (--i <= 0 || len <= 0) -- break; -- sg = sg_next(sg); -- buf = sg_dma_address(sg); -- this_sg_len = min_t(int, sg_dma_len(sg), len); -- } -- -- qtd_prev = qtd; -- qtd = fotg210_qtd_alloc(fotg210, flags); -- if (unlikely(!qtd)) -- goto cleanup; -- qtd->urb = urb; -- qtd_prev->hw_next = QTD_NEXT(fotg210, qtd->qtd_dma); -- list_add_tail(&qtd->qtd_list, head); -- } -- -- /* -- * unless the caller requires manual cleanup after short reads, -- * have the alt_next mechanism keep the queue running after the -- * last data qtd (the only one, for control and most other cases). -- */ -- if (likely((urb->transfer_flags & URB_SHORT_NOT_OK) == 0 || -- usb_pipecontrol(urb->pipe))) -- qtd->hw_alt_next = FOTG210_LIST_END(fotg210); -- -- /* -- * control requests may need a terminating data "status" ack; -- * other OUT ones may need a terminating short packet -- * (zero length). -- */ -- if (likely(urb->transfer_buffer_length != 0)) { -- int one_more = 0; -- -- if (usb_pipecontrol(urb->pipe)) { -- one_more = 1; -- token ^= 0x0100; /* "in" <--> "out" */ -- token |= QTD_TOGGLE; /* force DATA1 */ -- } else if (usb_pipeout(urb->pipe) -- && (urb->transfer_flags & URB_ZERO_PACKET) -- && !(urb->transfer_buffer_length % maxpacket)) { -- one_more = 1; -- } -- if (one_more) { -- qtd_prev = qtd; -- qtd = fotg210_qtd_alloc(fotg210, flags); -- if (unlikely(!qtd)) -- goto cleanup; -- qtd->urb = urb; -- qtd_prev->hw_next = QTD_NEXT(fotg210, qtd->qtd_dma); -- list_add_tail(&qtd->qtd_list, head); -- -- /* never any data in such packets */ -- qtd_fill(fotg210, qtd, 0, 0, token, 0); -- } -- } -- -- /* by default, enable interrupt on urb completion */ -- if (likely(!(urb->transfer_flags & URB_NO_INTERRUPT))) -- qtd->hw_token |= cpu_to_hc32(fotg210, QTD_IOC); -- return head; -- --cleanup: -- qtd_list_free(fotg210, urb, head); -- return NULL; --} -- --/* Would be best to create all qh's from config descriptors, -- * when each interface/altsetting is established. Unlink -- * any previous qh and cancel its urbs first; endpoints are -- * implicitly reset then (data toggle too). -- * That'd mean updating how usbcore talks to HCDs. (2.7?) -- */ -- -- --/* Each QH holds a qtd list; a QH is used for everything except iso. -- * -- * For interrupt urbs, the scheduler must set the microframe scheduling -- * mask(s) each time the QH gets scheduled. For highspeed, that's -- * just one microframe in the s-mask. For split interrupt transactions -- * there are additional complications: c-mask, maybe FSTNs. -- */ --static struct fotg210_qh *qh_make(struct fotg210_hcd *fotg210, struct urb *urb, -- gfp_t flags) --{ -- struct fotg210_qh *qh = fotg210_qh_alloc(fotg210, flags); -- struct usb_host_endpoint *ep; -- u32 info1 = 0, info2 = 0; -- int is_input, type; -- int maxp = 0; -- int mult; -- struct usb_tt *tt = urb->dev->tt; -- struct fotg210_qh_hw *hw; -- -- if (!qh) -- return qh; -- -- /* -- * init endpoint/device data for this QH -- */ -- info1 |= usb_pipeendpoint(urb->pipe) << 8; -- info1 |= usb_pipedevice(urb->pipe) << 0; -- -- is_input = usb_pipein(urb->pipe); -- type = usb_pipetype(urb->pipe); -- ep = usb_pipe_endpoint(urb->dev, urb->pipe); -- maxp = usb_endpoint_maxp(&ep->desc); -- mult = usb_endpoint_maxp_mult(&ep->desc); -- -- /* 1024 byte maxpacket is a hardware ceiling. High bandwidth -- * acts like up to 3KB, but is built from smaller packets. -- */ -- if (maxp > 1024) { -- fotg210_dbg(fotg210, "bogus qh maxpacket %d\n", maxp); -- goto done; -- } -- -- /* Compute interrupt scheduling parameters just once, and save. -- * - allowing for high bandwidth, how many nsec/uframe are used? -- * - split transactions need a second CSPLIT uframe; same question -- * - splits also need a schedule gap (for full/low speed I/O) -- * - qh has a polling interval -- * -- * For control/bulk requests, the HC or TT handles these. -- */ -- if (type == PIPE_INTERRUPT) { -- qh->usecs = NS_TO_US(usb_calc_bus_time(USB_SPEED_HIGH, -- is_input, 0, mult * maxp)); -- qh->start = NO_FRAME; -- -- if (urb->dev->speed == USB_SPEED_HIGH) { -- qh->c_usecs = 0; -- qh->gap_uf = 0; -- -- qh->period = urb->interval >> 3; -- if (qh->period == 0 && urb->interval != 1) { -- /* NOTE interval 2 or 4 uframes could work. -- * But interval 1 scheduling is simpler, and -- * includes high bandwidth. -- */ -- urb->interval = 1; -- } else if (qh->period > fotg210->periodic_size) { -- qh->period = fotg210->periodic_size; -- urb->interval = qh->period << 3; -- } -- } else { -- int think_time; -- -- /* gap is f(FS/LS transfer times) */ -- qh->gap_uf = 1 + usb_calc_bus_time(urb->dev->speed, -- is_input, 0, maxp) / (125 * 1000); -- -- /* FIXME this just approximates SPLIT/CSPLIT times */ -- if (is_input) { /* SPLIT, gap, CSPLIT+DATA */ -- qh->c_usecs = qh->usecs + HS_USECS(0); -- qh->usecs = HS_USECS(1); -- } else { /* SPLIT+DATA, gap, CSPLIT */ -- qh->usecs += HS_USECS(1); -- qh->c_usecs = HS_USECS(0); -- } -- -- think_time = tt ? tt->think_time : 0; -- qh->tt_usecs = NS_TO_US(think_time + -- usb_calc_bus_time(urb->dev->speed, -- is_input, 0, maxp)); -- qh->period = urb->interval; -- if (qh->period > fotg210->periodic_size) { -- qh->period = fotg210->periodic_size; -- urb->interval = qh->period; -- } -- } -- } -- -- /* support for tt scheduling, and access to toggles */ -- qh->dev = urb->dev; -- -- /* using TT? */ -- switch (urb->dev->speed) { -- case USB_SPEED_LOW: -- info1 |= QH_LOW_SPEED; -- fallthrough; -- -- case USB_SPEED_FULL: -- /* EPS 0 means "full" */ -- if (type != PIPE_INTERRUPT) -- info1 |= (FOTG210_TUNE_RL_TT << 28); -- if (type == PIPE_CONTROL) { -- info1 |= QH_CONTROL_EP; /* for TT */ -- info1 |= QH_TOGGLE_CTL; /* toggle from qtd */ -- } -- info1 |= maxp << 16; -- -- info2 |= (FOTG210_TUNE_MULT_TT << 30); -- -- /* Some Freescale processors have an erratum in which the -- * port number in the queue head was 0..N-1 instead of 1..N. -- */ -- if (fotg210_has_fsl_portno_bug(fotg210)) -- info2 |= (urb->dev->ttport-1) << 23; -- else -- info2 |= urb->dev->ttport << 23; -- -- /* set the address of the TT; for TDI's integrated -- * root hub tt, leave it zeroed. -- */ -- if (tt && tt->hub != fotg210_to_hcd(fotg210)->self.root_hub) -- info2 |= tt->hub->devnum << 16; -- -- /* NOTE: if (PIPE_INTERRUPT) { scheduler sets c-mask } */ -- -- break; -- -- case USB_SPEED_HIGH: /* no TT involved */ -- info1 |= QH_HIGH_SPEED; -- if (type == PIPE_CONTROL) { -- info1 |= (FOTG210_TUNE_RL_HS << 28); -- info1 |= 64 << 16; /* usb2 fixed maxpacket */ -- info1 |= QH_TOGGLE_CTL; /* toggle from qtd */ -- info2 |= (FOTG210_TUNE_MULT_HS << 30); -- } else if (type == PIPE_BULK) { -- info1 |= (FOTG210_TUNE_RL_HS << 28); -- /* The USB spec says that high speed bulk endpoints -- * always use 512 byte maxpacket. But some device -- * vendors decided to ignore that, and MSFT is happy -- * to help them do so. So now people expect to use -- * such nonconformant devices with Linux too; sigh. -- */ -- info1 |= maxp << 16; -- info2 |= (FOTG210_TUNE_MULT_HS << 30); -- } else { /* PIPE_INTERRUPT */ -- info1 |= maxp << 16; -- info2 |= mult << 30; -- } -- break; -- default: -- fotg210_dbg(fotg210, "bogus dev %p speed %d\n", urb->dev, -- urb->dev->speed); --done: -- qh_destroy(fotg210, qh); -- return NULL; -- } -- -- /* NOTE: if (PIPE_INTERRUPT) { scheduler sets s-mask } */ -- -- /* init as live, toggle clear, advance to dummy */ -- qh->qh_state = QH_STATE_IDLE; -- hw = qh->hw; -- hw->hw_info1 = cpu_to_hc32(fotg210, info1); -- hw->hw_info2 = cpu_to_hc32(fotg210, info2); -- qh->is_out = !is_input; -- usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), !is_input, 1); -- qh_refresh(fotg210, qh); -- return qh; --} -- --static void enable_async(struct fotg210_hcd *fotg210) --{ -- if (fotg210->async_count++) -- return; -- -- /* Stop waiting to turn off the async schedule */ -- fotg210->enabled_hrtimer_events &= ~BIT(FOTG210_HRTIMER_DISABLE_ASYNC); -- -- /* Don't start the schedule until ASS is 0 */ -- fotg210_poll_ASS(fotg210); -- turn_on_io_watchdog(fotg210); --} -- --static void disable_async(struct fotg210_hcd *fotg210) --{ -- if (--fotg210->async_count) -- return; -- -- /* The async schedule and async_unlink list are supposed to be empty */ -- WARN_ON(fotg210->async->qh_next.qh || fotg210->async_unlink); -- -- /* Don't turn off the schedule until ASS is 1 */ -- fotg210_poll_ASS(fotg210); --} -- --/* move qh (and its qtds) onto async queue; maybe enable queue. */ -- --static void qh_link_async(struct fotg210_hcd *fotg210, struct fotg210_qh *qh) --{ -- __hc32 dma = QH_NEXT(fotg210, qh->qh_dma); -- struct fotg210_qh *head; -- -- /* Don't link a QH if there's a Clear-TT-Buffer pending */ -- if (unlikely(qh->clearing_tt)) -- return; -- -- WARN_ON(qh->qh_state != QH_STATE_IDLE); -- -- /* clear halt and/or toggle; and maybe recover from silicon quirk */ -- qh_refresh(fotg210, qh); -- -- /* splice right after start */ -- head = fotg210->async; -- qh->qh_next = head->qh_next; -- qh->hw->hw_next = head->hw->hw_next; -- wmb(); -- -- head->qh_next.qh = qh; -- head->hw->hw_next = dma; -- -- qh->xacterrs = 0; -- qh->qh_state = QH_STATE_LINKED; -- /* qtd completions reported later by interrupt */ -- -- enable_async(fotg210); --} -- --/* For control/bulk/interrupt, return QH with these TDs appended. -- * Allocates and initializes the QH if necessary. -- * Returns null if it can't allocate a QH it needs to. -- * If the QH has TDs (urbs) already, that's great. -- */ --static struct fotg210_qh *qh_append_tds(struct fotg210_hcd *fotg210, -- struct urb *urb, struct list_head *qtd_list, -- int epnum, void **ptr) --{ -- struct fotg210_qh *qh = NULL; -- __hc32 qh_addr_mask = cpu_to_hc32(fotg210, 0x7f); -- -- qh = (struct fotg210_qh *) *ptr; -- if (unlikely(qh == NULL)) { -- /* can't sleep here, we have fotg210->lock... */ -- qh = qh_make(fotg210, urb, GFP_ATOMIC); -- *ptr = qh; -- } -- if (likely(qh != NULL)) { -- struct fotg210_qtd *qtd; -- -- if (unlikely(list_empty(qtd_list))) -- qtd = NULL; -- else -- qtd = list_entry(qtd_list->next, struct fotg210_qtd, -- qtd_list); -- -- /* control qh may need patching ... */ -- if (unlikely(epnum == 0)) { -- /* usb_reset_device() briefly reverts to address 0 */ -- if (usb_pipedevice(urb->pipe) == 0) -- qh->hw->hw_info1 &= ~qh_addr_mask; -- } -- -- /* just one way to queue requests: swap with the dummy qtd. -- * only hc or qh_refresh() ever modify the overlay. -- */ -- if (likely(qtd != NULL)) { -- struct fotg210_qtd *dummy; -- dma_addr_t dma; -- __hc32 token; -- -- /* to avoid racing the HC, use the dummy td instead of -- * the first td of our list (becomes new dummy). both -- * tds stay deactivated until we're done, when the -- * HC is allowed to fetch the old dummy (4.10.2). -- */ -- token = qtd->hw_token; -- qtd->hw_token = HALT_BIT(fotg210); -- -- dummy = qh->dummy; -- -- dma = dummy->qtd_dma; -- *dummy = *qtd; -- dummy->qtd_dma = dma; -- -- list_del(&qtd->qtd_list); -- list_add(&dummy->qtd_list, qtd_list); -- list_splice_tail(qtd_list, &qh->qtd_list); -- -- fotg210_qtd_init(fotg210, qtd, qtd->qtd_dma); -- qh->dummy = qtd; -- -- /* hc must see the new dummy at list end */ -- dma = qtd->qtd_dma; -- qtd = list_entry(qh->qtd_list.prev, -- struct fotg210_qtd, qtd_list); -- qtd->hw_next = QTD_NEXT(fotg210, dma); -- -- /* let the hc process these next qtds */ -- wmb(); -- dummy->hw_token = token; -- -- urb->hcpriv = qh; -- } -- } -- return qh; --} -- --static int submit_async(struct fotg210_hcd *fotg210, struct urb *urb, -- struct list_head *qtd_list, gfp_t mem_flags) --{ -- int epnum; -- unsigned long flags; -- struct fotg210_qh *qh = NULL; -- int rc; -- -- epnum = urb->ep->desc.bEndpointAddress; -- --#ifdef FOTG210_URB_TRACE -- { -- struct fotg210_qtd *qtd; -- -- qtd = list_entry(qtd_list->next, struct fotg210_qtd, qtd_list); -- fotg210_dbg(fotg210, -- "%s %s urb %p ep%d%s len %d, qtd %p [qh %p]\n", -- __func__, urb->dev->devpath, urb, -- epnum & 0x0f, (epnum & USB_DIR_IN) -- ? "in" : "out", -- urb->transfer_buffer_length, -- qtd, urb->ep->hcpriv); -- } --#endif -- -- spin_lock_irqsave(&fotg210->lock, flags); -- if (unlikely(!HCD_HW_ACCESSIBLE(fotg210_to_hcd(fotg210)))) { -- rc = -ESHUTDOWN; -- goto done; -- } -- rc = usb_hcd_link_urb_to_ep(fotg210_to_hcd(fotg210), urb); -- if (unlikely(rc)) -- goto done; -- -- qh = qh_append_tds(fotg210, urb, qtd_list, epnum, &urb->ep->hcpriv); -- if (unlikely(qh == NULL)) { -- usb_hcd_unlink_urb_from_ep(fotg210_to_hcd(fotg210), urb); -- rc = -ENOMEM; -- goto done; -- } -- -- /* Control/bulk operations through TTs don't need scheduling, -- * the HC and TT handle it when the TT has a buffer ready. -- */ -- if (likely(qh->qh_state == QH_STATE_IDLE)) -- qh_link_async(fotg210, qh); --done: -- spin_unlock_irqrestore(&fotg210->lock, flags); -- if (unlikely(qh == NULL)) -- qtd_list_free(fotg210, urb, qtd_list); -- return rc; --} -- --static void single_unlink_async(struct fotg210_hcd *fotg210, -- struct fotg210_qh *qh) --{ -- struct fotg210_qh *prev; -- -- /* Add to the end of the list of QHs waiting for the next IAAD */ -- qh->qh_state = QH_STATE_UNLINK; -- if (fotg210->async_unlink) -- fotg210->async_unlink_last->unlink_next = qh; -- else -- fotg210->async_unlink = qh; -- fotg210->async_unlink_last = qh; -- -- /* Unlink it from the schedule */ -- prev = fotg210->async; -- while (prev->qh_next.qh != qh) -- prev = prev->qh_next.qh; -- -- prev->hw->hw_next = qh->hw->hw_next; -- prev->qh_next = qh->qh_next; -- if (fotg210->qh_scan_next == qh) -- fotg210->qh_scan_next = qh->qh_next.qh; --} -- --static void start_iaa_cycle(struct fotg210_hcd *fotg210, bool nested) --{ -- /* -- * Do nothing if an IAA cycle is already running or -- * if one will be started shortly. -- */ -- if (fotg210->async_iaa || fotg210->async_unlinking) -- return; -- -- /* Do all the waiting QHs at once */ -- fotg210->async_iaa = fotg210->async_unlink; -- fotg210->async_unlink = NULL; -- -- /* If the controller isn't running, we don't have to wait for it */ -- if (unlikely(fotg210->rh_state < FOTG210_RH_RUNNING)) { -- if (!nested) /* Avoid recursion */ -- end_unlink_async(fotg210); -- -- /* Otherwise start a new IAA cycle */ -- } else if (likely(fotg210->rh_state == FOTG210_RH_RUNNING)) { -- /* Make sure the unlinks are all visible to the hardware */ -- wmb(); -- -- fotg210_writel(fotg210, fotg210->command | CMD_IAAD, -- &fotg210->regs->command); -- fotg210_readl(fotg210, &fotg210->regs->command); -- fotg210_enable_event(fotg210, FOTG210_HRTIMER_IAA_WATCHDOG, -- true); -- } --} -- --/* the async qh for the qtds being unlinked are now gone from the HC */ -- --static void end_unlink_async(struct fotg210_hcd *fotg210) --{ -- struct fotg210_qh *qh; -- -- /* Process the idle QHs */ --restart: -- fotg210->async_unlinking = true; -- while (fotg210->async_iaa) { -- qh = fotg210->async_iaa; -- fotg210->async_iaa = qh->unlink_next; -- qh->unlink_next = NULL; -- -- qh->qh_state = QH_STATE_IDLE; -- qh->qh_next.qh = NULL; -- -- qh_completions(fotg210, qh); -- if (!list_empty(&qh->qtd_list) && -- fotg210->rh_state == FOTG210_RH_RUNNING) -- qh_link_async(fotg210, qh); -- disable_async(fotg210); -- } -- fotg210->async_unlinking = false; -- -- /* Start a new IAA cycle if any QHs are waiting for it */ -- if (fotg210->async_unlink) { -- start_iaa_cycle(fotg210, true); -- if (unlikely(fotg210->rh_state < FOTG210_RH_RUNNING)) -- goto restart; -- } --} -- --static void unlink_empty_async(struct fotg210_hcd *fotg210) --{ -- struct fotg210_qh *qh, *next; -- bool stopped = (fotg210->rh_state < FOTG210_RH_RUNNING); -- bool check_unlinks_later = false; -- -- /* Unlink all the async QHs that have been empty for a timer cycle */ -- next = fotg210->async->qh_next.qh; -- while (next) { -- qh = next; -- next = qh->qh_next.qh; -- -- if (list_empty(&qh->qtd_list) && -- qh->qh_state == QH_STATE_LINKED) { -- if (!stopped && qh->unlink_cycle == -- fotg210->async_unlink_cycle) -- check_unlinks_later = true; -- else -- single_unlink_async(fotg210, qh); -- } -- } -- -- /* Start a new IAA cycle if any QHs are waiting for it */ -- if (fotg210->async_unlink) -- start_iaa_cycle(fotg210, false); -- -- /* QHs that haven't been empty for long enough will be handled later */ -- if (check_unlinks_later) { -- fotg210_enable_event(fotg210, FOTG210_HRTIMER_ASYNC_UNLINKS, -- true); -- ++fotg210->async_unlink_cycle; -- } --} -- --/* makes sure the async qh will become idle */ --/* caller must own fotg210->lock */ -- --static void start_unlink_async(struct fotg210_hcd *fotg210, -- struct fotg210_qh *qh) --{ -- /* -- * If the QH isn't linked then there's nothing we can do -- * unless we were called during a giveback, in which case -- * qh_completions() has to deal with it. -- */ -- if (qh->qh_state != QH_STATE_LINKED) { -- if (qh->qh_state == QH_STATE_COMPLETING) -- qh->needs_rescan = 1; -- return; -- } -- -- single_unlink_async(fotg210, qh); -- start_iaa_cycle(fotg210, false); --} -- --static void scan_async(struct fotg210_hcd *fotg210) --{ -- struct fotg210_qh *qh; -- bool check_unlinks_later = false; -- -- fotg210->qh_scan_next = fotg210->async->qh_next.qh; -- while (fotg210->qh_scan_next) { -- qh = fotg210->qh_scan_next; -- fotg210->qh_scan_next = qh->qh_next.qh; --rescan: -- /* clean any finished work for this qh */ -- if (!list_empty(&qh->qtd_list)) { -- int temp; -- -- /* -- * Unlinks could happen here; completion reporting -- * drops the lock. That's why fotg210->qh_scan_next -- * always holds the next qh to scan; if the next qh -- * gets unlinked then fotg210->qh_scan_next is adjusted -- * in single_unlink_async(). -- */ -- temp = qh_completions(fotg210, qh); -- if (qh->needs_rescan) { -- start_unlink_async(fotg210, qh); -- } else if (list_empty(&qh->qtd_list) -- && qh->qh_state == QH_STATE_LINKED) { -- qh->unlink_cycle = fotg210->async_unlink_cycle; -- check_unlinks_later = true; -- } else if (temp != 0) -- goto rescan; -- } -- } -- -- /* -- * Unlink empty entries, reducing DMA usage as well -- * as HCD schedule-scanning costs. Delay for any qh -- * we just scanned, there's a not-unusual case that it -- * doesn't stay idle for long. -- */ -- if (check_unlinks_later && fotg210->rh_state == FOTG210_RH_RUNNING && -- !(fotg210->enabled_hrtimer_events & -- BIT(FOTG210_HRTIMER_ASYNC_UNLINKS))) { -- fotg210_enable_event(fotg210, -- FOTG210_HRTIMER_ASYNC_UNLINKS, true); -- ++fotg210->async_unlink_cycle; -- } --} --/* EHCI scheduled transaction support: interrupt, iso, split iso -- * These are called "periodic" transactions in the EHCI spec. -- * -- * Note that for interrupt transfers, the QH/QTD manipulation is shared -- * with the "asynchronous" transaction support (control/bulk transfers). -- * The only real difference is in how interrupt transfers are scheduled. -- * -- * For ISO, we make an "iso_stream" head to serve the same role as a QH. -- * It keeps track of every ITD (or SITD) that's linked, and holds enough -- * pre-calculated schedule data to make appending to the queue be quick. -- */ --static int fotg210_get_frame(struct usb_hcd *hcd); -- --/* periodic_next_shadow - return "next" pointer on shadow list -- * @periodic: host pointer to qh/itd -- * @tag: hardware tag for type of this record -- */ --static union fotg210_shadow *periodic_next_shadow(struct fotg210_hcd *fotg210, -- union fotg210_shadow *periodic, __hc32 tag) --{ -- switch (hc32_to_cpu(fotg210, tag)) { -- case Q_TYPE_QH: -- return &periodic->qh->qh_next; -- case Q_TYPE_FSTN: -- return &periodic->fstn->fstn_next; -- default: -- return &periodic->itd->itd_next; -- } --} -- --static __hc32 *shadow_next_periodic(struct fotg210_hcd *fotg210, -- union fotg210_shadow *periodic, __hc32 tag) --{ -- switch (hc32_to_cpu(fotg210, tag)) { -- /* our fotg210_shadow.qh is actually software part */ -- case Q_TYPE_QH: -- return &periodic->qh->hw->hw_next; -- /* others are hw parts */ -- default: -- return periodic->hw_next; -- } --} -- --/* caller must hold fotg210->lock */ --static void periodic_unlink(struct fotg210_hcd *fotg210, unsigned frame, -- void *ptr) --{ -- union fotg210_shadow *prev_p = &fotg210->pshadow[frame]; -- __hc32 *hw_p = &fotg210->periodic[frame]; -- union fotg210_shadow here = *prev_p; -- -- /* find predecessor of "ptr"; hw and shadow lists are in sync */ -- while (here.ptr && here.ptr != ptr) { -- prev_p = periodic_next_shadow(fotg210, prev_p, -- Q_NEXT_TYPE(fotg210, *hw_p)); -- hw_p = shadow_next_periodic(fotg210, &here, -- Q_NEXT_TYPE(fotg210, *hw_p)); -- here = *prev_p; -- } -- /* an interrupt entry (at list end) could have been shared */ -- if (!here.ptr) -- return; -- -- /* update shadow and hardware lists ... the old "next" pointers -- * from ptr may still be in use, the caller updates them. -- */ -- *prev_p = *periodic_next_shadow(fotg210, &here, -- Q_NEXT_TYPE(fotg210, *hw_p)); -- -- *hw_p = *shadow_next_periodic(fotg210, &here, -- Q_NEXT_TYPE(fotg210, *hw_p)); --} -- --/* how many of the uframe's 125 usecs are allocated? */ --static unsigned short periodic_usecs(struct fotg210_hcd *fotg210, -- unsigned frame, unsigned uframe) --{ -- __hc32 *hw_p = &fotg210->periodic[frame]; -- union fotg210_shadow *q = &fotg210->pshadow[frame]; -- unsigned usecs = 0; -- struct fotg210_qh_hw *hw; -- -- while (q->ptr) { -- switch (hc32_to_cpu(fotg210, Q_NEXT_TYPE(fotg210, *hw_p))) { -- case Q_TYPE_QH: -- hw = q->qh->hw; -- /* is it in the S-mask? */ -- if (hw->hw_info2 & cpu_to_hc32(fotg210, 1 << uframe)) -- usecs += q->qh->usecs; -- /* ... or C-mask? */ -- if (hw->hw_info2 & cpu_to_hc32(fotg210, -- 1 << (8 + uframe))) -- usecs += q->qh->c_usecs; -- hw_p = &hw->hw_next; -- q = &q->qh->qh_next; -- break; -- /* case Q_TYPE_FSTN: */ -- default: -- /* for "save place" FSTNs, count the relevant INTR -- * bandwidth from the previous frame -- */ -- if (q->fstn->hw_prev != FOTG210_LIST_END(fotg210)) -- fotg210_dbg(fotg210, "ignoring FSTN cost ...\n"); -- -- hw_p = &q->fstn->hw_next; -- q = &q->fstn->fstn_next; -- break; -- case Q_TYPE_ITD: -- if (q->itd->hw_transaction[uframe]) -- usecs += q->itd->stream->usecs; -- hw_p = &q->itd->hw_next; -- q = &q->itd->itd_next; -- break; -- } -- } -- if (usecs > fotg210->uframe_periodic_max) -- fotg210_err(fotg210, "uframe %d sched overrun: %d usecs\n", -- frame * 8 + uframe, usecs); -- return usecs; --} -- --static int same_tt(struct usb_device *dev1, struct usb_device *dev2) --{ -- if (!dev1->tt || !dev2->tt) -- return 0; -- if (dev1->tt != dev2->tt) -- return 0; -- if (dev1->tt->multi) -- return dev1->ttport == dev2->ttport; -- else -- return 1; --} -- --/* return true iff the device's transaction translator is available -- * for a periodic transfer starting at the specified frame, using -- * all the uframes in the mask. -- */ --static int tt_no_collision(struct fotg210_hcd *fotg210, unsigned period, -- struct usb_device *dev, unsigned frame, u32 uf_mask) --{ -- if (period == 0) /* error */ -- return 0; -- -- /* note bandwidth wastage: split never follows csplit -- * (different dev or endpoint) until the next uframe. -- * calling convention doesn't make that distinction. -- */ -- for (; frame < fotg210->periodic_size; frame += period) { -- union fotg210_shadow here; -- __hc32 type; -- struct fotg210_qh_hw *hw; -- -- here = fotg210->pshadow[frame]; -- type = Q_NEXT_TYPE(fotg210, fotg210->periodic[frame]); -- while (here.ptr) { -- switch (hc32_to_cpu(fotg210, type)) { -- case Q_TYPE_ITD: -- type = Q_NEXT_TYPE(fotg210, here.itd->hw_next); -- here = here.itd->itd_next; -- continue; -- case Q_TYPE_QH: -- hw = here.qh->hw; -- if (same_tt(dev, here.qh->dev)) { -- u32 mask; -- -- mask = hc32_to_cpu(fotg210, -- hw->hw_info2); -- /* "knows" no gap is needed */ -- mask |= mask >> 8; -- if (mask & uf_mask) -- break; -- } -- type = Q_NEXT_TYPE(fotg210, hw->hw_next); -- here = here.qh->qh_next; -- continue; -- /* case Q_TYPE_FSTN: */ -- default: -- fotg210_dbg(fotg210, -- "periodic frame %d bogus type %d\n", -- frame, type); -- } -- -- /* collision or error */ -- return 0; -- } -- } -- -- /* no collision */ -- return 1; --} -- --static void enable_periodic(struct fotg210_hcd *fotg210) --{ -- if (fotg210->periodic_count++) -- return; -- -- /* Stop waiting to turn off the periodic schedule */ -- fotg210->enabled_hrtimer_events &= -- ~BIT(FOTG210_HRTIMER_DISABLE_PERIODIC); -- -- /* Don't start the schedule until PSS is 0 */ -- fotg210_poll_PSS(fotg210); -- turn_on_io_watchdog(fotg210); --} -- --static void disable_periodic(struct fotg210_hcd *fotg210) --{ -- if (--fotg210->periodic_count) -- return; -- -- /* Don't turn off the schedule until PSS is 1 */ -- fotg210_poll_PSS(fotg210); --} -- --/* periodic schedule slots have iso tds (normal or split) first, then a -- * sparse tree for active interrupt transfers. -- * -- * this just links in a qh; caller guarantees uframe masks are set right. -- * no FSTN support (yet; fotg210 0.96+) -- */ --static void qh_link_periodic(struct fotg210_hcd *fotg210, struct fotg210_qh *qh) --{ -- unsigned i; -- unsigned period = qh->period; -- -- dev_dbg(&qh->dev->dev, -- "link qh%d-%04x/%p start %d [%d/%d us]\n", period, -- hc32_to_cpup(fotg210, &qh->hw->hw_info2) & -- (QH_CMASK | QH_SMASK), qh, qh->start, qh->usecs, -- qh->c_usecs); -- -- /* high bandwidth, or otherwise every microframe */ -- if (period == 0) -- period = 1; -- -- for (i = qh->start; i < fotg210->periodic_size; i += period) { -- union fotg210_shadow *prev = &fotg210->pshadow[i]; -- __hc32 *hw_p = &fotg210->periodic[i]; -- union fotg210_shadow here = *prev; -- __hc32 type = 0; -- -- /* skip the iso nodes at list head */ -- while (here.ptr) { -- type = Q_NEXT_TYPE(fotg210, *hw_p); -- if (type == cpu_to_hc32(fotg210, Q_TYPE_QH)) -- break; -- prev = periodic_next_shadow(fotg210, prev, type); -- hw_p = shadow_next_periodic(fotg210, &here, type); -- here = *prev; -- } -- -- /* sorting each branch by period (slow-->fast) -- * enables sharing interior tree nodes -- */ -- while (here.ptr && qh != here.qh) { -- if (qh->period > here.qh->period) -- break; -- prev = &here.qh->qh_next; -- hw_p = &here.qh->hw->hw_next; -- here = *prev; -- } -- /* link in this qh, unless some earlier pass did that */ -- if (qh != here.qh) { -- qh->qh_next = here; -- if (here.qh) -- qh->hw->hw_next = *hw_p; -- wmb(); -- prev->qh = qh; -- *hw_p = QH_NEXT(fotg210, qh->qh_dma); -- } -- } -- qh->qh_state = QH_STATE_LINKED; -- qh->xacterrs = 0; -- -- /* update per-qh bandwidth for usbfs */ -- fotg210_to_hcd(fotg210)->self.bandwidth_allocated += qh->period -- ? ((qh->usecs + qh->c_usecs) / qh->period) -- : (qh->usecs * 8); -- -- list_add(&qh->intr_node, &fotg210->intr_qh_list); -- -- /* maybe enable periodic schedule processing */ -- ++fotg210->intr_count; -- enable_periodic(fotg210); --} -- --static void qh_unlink_periodic(struct fotg210_hcd *fotg210, -- struct fotg210_qh *qh) --{ -- unsigned i; -- unsigned period; -- -- /* -- * If qh is for a low/full-speed device, simply unlinking it -- * could interfere with an ongoing split transaction. To unlink -- * it safely would require setting the QH_INACTIVATE bit and -- * waiting at least one frame, as described in EHCI 4.12.2.5. -- * -- * We won't bother with any of this. Instead, we assume that the -- * only reason for unlinking an interrupt QH while the current URB -- * is still active is to dequeue all the URBs (flush the whole -- * endpoint queue). -- * -- * If rebalancing the periodic schedule is ever implemented, this -- * approach will no longer be valid. -- */ -- -- /* high bandwidth, or otherwise part of every microframe */ -- period = qh->period; -- if (!period) -- period = 1; -- -- for (i = qh->start; i < fotg210->periodic_size; i += period) -- periodic_unlink(fotg210, i, qh); -- -- /* update per-qh bandwidth for usbfs */ -- fotg210_to_hcd(fotg210)->self.bandwidth_allocated -= qh->period -- ? ((qh->usecs + qh->c_usecs) / qh->period) -- : (qh->usecs * 8); -- -- dev_dbg(&qh->dev->dev, -- "unlink qh%d-%04x/%p start %d [%d/%d us]\n", -- qh->period, hc32_to_cpup(fotg210, &qh->hw->hw_info2) & -- (QH_CMASK | QH_SMASK), qh, qh->start, qh->usecs, -- qh->c_usecs); -- -- /* qh->qh_next still "live" to HC */ -- qh->qh_state = QH_STATE_UNLINK; -- qh->qh_next.ptr = NULL; -- -- if (fotg210->qh_scan_next == qh) -- fotg210->qh_scan_next = list_entry(qh->intr_node.next, -- struct fotg210_qh, intr_node); -- list_del(&qh->intr_node); --} -- --static void start_unlink_intr(struct fotg210_hcd *fotg210, -- struct fotg210_qh *qh) --{ -- /* If the QH isn't linked then there's nothing we can do -- * unless we were called during a giveback, in which case -- * qh_completions() has to deal with it. -- */ -- if (qh->qh_state != QH_STATE_LINKED) { -- if (qh->qh_state == QH_STATE_COMPLETING) -- qh->needs_rescan = 1; -- return; -- } -- -- qh_unlink_periodic(fotg210, qh); -- -- /* Make sure the unlinks are visible before starting the timer */ -- wmb(); -- -- /* -- * The EHCI spec doesn't say how long it takes the controller to -- * stop accessing an unlinked interrupt QH. The timer delay is -- * 9 uframes; presumably that will be long enough. -- */ -- qh->unlink_cycle = fotg210->intr_unlink_cycle; -- -- /* New entries go at the end of the intr_unlink list */ -- if (fotg210->intr_unlink) -- fotg210->intr_unlink_last->unlink_next = qh; -- else -- fotg210->intr_unlink = qh; -- fotg210->intr_unlink_last = qh; -- -- if (fotg210->intr_unlinking) -- ; /* Avoid recursive calls */ -- else if (fotg210->rh_state < FOTG210_RH_RUNNING) -- fotg210_handle_intr_unlinks(fotg210); -- else if (fotg210->intr_unlink == qh) { -- fotg210_enable_event(fotg210, FOTG210_HRTIMER_UNLINK_INTR, -- true); -- ++fotg210->intr_unlink_cycle; -- } --} -- --static void end_unlink_intr(struct fotg210_hcd *fotg210, struct fotg210_qh *qh) --{ -- struct fotg210_qh_hw *hw = qh->hw; -- int rc; -- -- qh->qh_state = QH_STATE_IDLE; -- hw->hw_next = FOTG210_LIST_END(fotg210); -- -- qh_completions(fotg210, qh); -- -- /* reschedule QH iff another request is queued */ -- if (!list_empty(&qh->qtd_list) && -- fotg210->rh_state == FOTG210_RH_RUNNING) { -- rc = qh_schedule(fotg210, qh); -- -- /* An error here likely indicates handshake failure -- * or no space left in the schedule. Neither fault -- * should happen often ... -- * -- * FIXME kill the now-dysfunctional queued urbs -- */ -- if (rc != 0) -- fotg210_err(fotg210, "can't reschedule qh %p, err %d\n", -- qh, rc); -- } -- -- /* maybe turn off periodic schedule */ -- --fotg210->intr_count; -- disable_periodic(fotg210); --} -- --static int check_period(struct fotg210_hcd *fotg210, unsigned frame, -- unsigned uframe, unsigned period, unsigned usecs) --{ -- int claimed; -- -- /* complete split running into next frame? -- * given FSTN support, we could sometimes check... -- */ -- if (uframe >= 8) -- return 0; -- -- /* convert "usecs we need" to "max already claimed" */ -- usecs = fotg210->uframe_periodic_max - usecs; -- -- /* we "know" 2 and 4 uframe intervals were rejected; so -- * for period 0, check _every_ microframe in the schedule. -- */ -- if (unlikely(period == 0)) { -- do { -- for (uframe = 0; uframe < 7; uframe++) { -- claimed = periodic_usecs(fotg210, frame, -- uframe); -- if (claimed > usecs) -- return 0; -- } -- } while ((frame += 1) < fotg210->periodic_size); -- -- /* just check the specified uframe, at that period */ -- } else { -- do { -- claimed = periodic_usecs(fotg210, frame, uframe); -- if (claimed > usecs) -- return 0; -- } while ((frame += period) < fotg210->periodic_size); -- } -- -- /* success! */ -- return 1; --} -- --static int check_intr_schedule(struct fotg210_hcd *fotg210, unsigned frame, -- unsigned uframe, const struct fotg210_qh *qh, __hc32 *c_maskp) --{ -- int retval = -ENOSPC; -- u8 mask = 0; -- -- if (qh->c_usecs && uframe >= 6) /* FSTN territory? */ -- goto done; -- -- if (!check_period(fotg210, frame, uframe, qh->period, qh->usecs)) -- goto done; -- if (!qh->c_usecs) { -- retval = 0; -- *c_maskp = 0; -- goto done; -- } -- -- /* Make sure this tt's buffer is also available for CSPLITs. -- * We pessimize a bit; probably the typical full speed case -- * doesn't need the second CSPLIT. -- * -- * NOTE: both SPLIT and CSPLIT could be checked in just -- * one smart pass... -- */ -- mask = 0x03 << (uframe + qh->gap_uf); -- *c_maskp = cpu_to_hc32(fotg210, mask << 8); -- -- mask |= 1 << uframe; -- if (tt_no_collision(fotg210, qh->period, qh->dev, frame, mask)) { -- if (!check_period(fotg210, frame, uframe + qh->gap_uf + 1, -- qh->period, qh->c_usecs)) -- goto done; -- if (!check_period(fotg210, frame, uframe + qh->gap_uf, -- qh->period, qh->c_usecs)) -- goto done; -- retval = 0; -- } --done: -- return retval; --} -- --/* "first fit" scheduling policy used the first time through, -- * or when the previous schedule slot can't be re-used. -- */ --static int qh_schedule(struct fotg210_hcd *fotg210, struct fotg210_qh *qh) --{ -- int status; -- unsigned uframe; -- __hc32 c_mask; -- unsigned frame; /* 0..(qh->period - 1), or NO_FRAME */ -- struct fotg210_qh_hw *hw = qh->hw; -- -- qh_refresh(fotg210, qh); -- hw->hw_next = FOTG210_LIST_END(fotg210); -- frame = qh->start; -- -- /* reuse the previous schedule slots, if we can */ -- if (frame < qh->period) { -- uframe = ffs(hc32_to_cpup(fotg210, &hw->hw_info2) & QH_SMASK); -- status = check_intr_schedule(fotg210, frame, --uframe, -- qh, &c_mask); -- } else { -- uframe = 0; -- c_mask = 0; -- status = -ENOSPC; -- } -- -- /* else scan the schedule to find a group of slots such that all -- * uframes have enough periodic bandwidth available. -- */ -- if (status) { -- /* "normal" case, uframing flexible except with splits */ -- if (qh->period) { -- int i; -- -- for (i = qh->period; status && i > 0; --i) { -- frame = ++fotg210->random_frame % qh->period; -- for (uframe = 0; uframe < 8; uframe++) { -- status = check_intr_schedule(fotg210, -- frame, uframe, qh, -- &c_mask); -- if (status == 0) -- break; -- } -- } -- -- /* qh->period == 0 means every uframe */ -- } else { -- frame = 0; -- status = check_intr_schedule(fotg210, 0, 0, qh, -- &c_mask); -- } -- if (status) -- goto done; -- qh->start = frame; -- -- /* reset S-frame and (maybe) C-frame masks */ -- hw->hw_info2 &= cpu_to_hc32(fotg210, ~(QH_CMASK | QH_SMASK)); -- hw->hw_info2 |= qh->period -- ? cpu_to_hc32(fotg210, 1 << uframe) -- : cpu_to_hc32(fotg210, QH_SMASK); -- hw->hw_info2 |= c_mask; -- } else -- fotg210_dbg(fotg210, "reused qh %p schedule\n", qh); -- -- /* stuff into the periodic schedule */ -- qh_link_periodic(fotg210, qh); --done: -- return status; --} -- --static int intr_submit(struct fotg210_hcd *fotg210, struct urb *urb, -- struct list_head *qtd_list, gfp_t mem_flags) --{ -- unsigned epnum; -- unsigned long flags; -- struct fotg210_qh *qh; -- int status; -- struct list_head empty; -- -- /* get endpoint and transfer/schedule data */ -- epnum = urb->ep->desc.bEndpointAddress; -- -- spin_lock_irqsave(&fotg210->lock, flags); -- -- if (unlikely(!HCD_HW_ACCESSIBLE(fotg210_to_hcd(fotg210)))) { -- status = -ESHUTDOWN; -- goto done_not_linked; -- } -- status = usb_hcd_link_urb_to_ep(fotg210_to_hcd(fotg210), urb); -- if (unlikely(status)) -- goto done_not_linked; -- -- /* get qh and force any scheduling errors */ -- INIT_LIST_HEAD(&empty); -- qh = qh_append_tds(fotg210, urb, &empty, epnum, &urb->ep->hcpriv); -- if (qh == NULL) { -- status = -ENOMEM; -- goto done; -- } -- if (qh->qh_state == QH_STATE_IDLE) { -- status = qh_schedule(fotg210, qh); -- if (status) -- goto done; -- } -- -- /* then queue the urb's tds to the qh */ -- qh = qh_append_tds(fotg210, urb, qtd_list, epnum, &urb->ep->hcpriv); -- BUG_ON(qh == NULL); -- -- /* ... update usbfs periodic stats */ -- fotg210_to_hcd(fotg210)->self.bandwidth_int_reqs++; -- --done: -- if (unlikely(status)) -- usb_hcd_unlink_urb_from_ep(fotg210_to_hcd(fotg210), urb); --done_not_linked: -- spin_unlock_irqrestore(&fotg210->lock, flags); -- if (status) -- qtd_list_free(fotg210, urb, qtd_list); -- -- return status; --} -- --static void scan_intr(struct fotg210_hcd *fotg210) --{ -- struct fotg210_qh *qh; -- -- list_for_each_entry_safe(qh, fotg210->qh_scan_next, -- &fotg210->intr_qh_list, intr_node) { --rescan: -- /* clean any finished work for this qh */ -- if (!list_empty(&qh->qtd_list)) { -- int temp; -- -- /* -- * Unlinks could happen here; completion reporting -- * drops the lock. That's why fotg210->qh_scan_next -- * always holds the next qh to scan; if the next qh -- * gets unlinked then fotg210->qh_scan_next is adjusted -- * in qh_unlink_periodic(). -- */ -- temp = qh_completions(fotg210, qh); -- if (unlikely(qh->needs_rescan || -- (list_empty(&qh->qtd_list) && -- qh->qh_state == QH_STATE_LINKED))) -- start_unlink_intr(fotg210, qh); -- else if (temp != 0) -- goto rescan; -- } -- } --} -- --/* fotg210_iso_stream ops work with both ITD and SITD */ -- --static struct fotg210_iso_stream *iso_stream_alloc(gfp_t mem_flags) --{ -- struct fotg210_iso_stream *stream; -- -- stream = kzalloc(sizeof(*stream), mem_flags); -- if (likely(stream != NULL)) { -- INIT_LIST_HEAD(&stream->td_list); -- INIT_LIST_HEAD(&stream->free_list); -- stream->next_uframe = -1; -- } -- return stream; --} -- --static void iso_stream_init(struct fotg210_hcd *fotg210, -- struct fotg210_iso_stream *stream, struct usb_device *dev, -- int pipe, unsigned interval) --{ -- u32 buf1; -- unsigned epnum, maxp; -- int is_input; -- long bandwidth; -- unsigned multi; -- struct usb_host_endpoint *ep; -- -- /* -- * this might be a "high bandwidth" highspeed endpoint, -- * as encoded in the ep descriptor's wMaxPacket field -- */ -- epnum = usb_pipeendpoint(pipe); -- is_input = usb_pipein(pipe) ? USB_DIR_IN : 0; -- ep = usb_pipe_endpoint(dev, pipe); -- maxp = usb_endpoint_maxp(&ep->desc); -- if (is_input) -- buf1 = (1 << 11); -- else -- buf1 = 0; -- -- multi = usb_endpoint_maxp_mult(&ep->desc); -- buf1 |= maxp; -- maxp *= multi; -- -- stream->buf0 = cpu_to_hc32(fotg210, (epnum << 8) | dev->devnum); -- stream->buf1 = cpu_to_hc32(fotg210, buf1); -- stream->buf2 = cpu_to_hc32(fotg210, multi); -- -- /* usbfs wants to report the average usecs per frame tied up -- * when transfers on this endpoint are scheduled ... -- */ -- if (dev->speed == USB_SPEED_FULL) { -- interval <<= 3; -- stream->usecs = NS_TO_US(usb_calc_bus_time(dev->speed, -- is_input, 1, maxp)); -- stream->usecs /= 8; -- } else { -- stream->highspeed = 1; -- stream->usecs = HS_USECS_ISO(maxp); -- } -- bandwidth = stream->usecs * 8; -- bandwidth /= interval; -- -- stream->bandwidth = bandwidth; -- stream->udev = dev; -- stream->bEndpointAddress = is_input | epnum; -- stream->interval = interval; -- stream->maxp = maxp; --} -- --static struct fotg210_iso_stream *iso_stream_find(struct fotg210_hcd *fotg210, -- struct urb *urb) --{ -- unsigned epnum; -- struct fotg210_iso_stream *stream; -- struct usb_host_endpoint *ep; -- unsigned long flags; -- -- epnum = usb_pipeendpoint(urb->pipe); -- if (usb_pipein(urb->pipe)) -- ep = urb->dev->ep_in[epnum]; -- else -- ep = urb->dev->ep_out[epnum]; -- -- spin_lock_irqsave(&fotg210->lock, flags); -- stream = ep->hcpriv; -- -- if (unlikely(stream == NULL)) { -- stream = iso_stream_alloc(GFP_ATOMIC); -- if (likely(stream != NULL)) { -- ep->hcpriv = stream; -- stream->ep = ep; -- iso_stream_init(fotg210, stream, urb->dev, urb->pipe, -- urb->interval); -- } -- -- /* if dev->ep[epnum] is a QH, hw is set */ -- } else if (unlikely(stream->hw != NULL)) { -- fotg210_dbg(fotg210, "dev %s ep%d%s, not iso??\n", -- urb->dev->devpath, epnum, -- usb_pipein(urb->pipe) ? "in" : "out"); -- stream = NULL; -- } -- -- spin_unlock_irqrestore(&fotg210->lock, flags); -- return stream; --} -- --/* fotg210_iso_sched ops can be ITD-only or SITD-only */ -- --static struct fotg210_iso_sched *iso_sched_alloc(unsigned packets, -- gfp_t mem_flags) --{ -- struct fotg210_iso_sched *iso_sched; -- -- iso_sched = kzalloc(struct_size(iso_sched, packet, packets), mem_flags); -- if (likely(iso_sched != NULL)) -- INIT_LIST_HEAD(&iso_sched->td_list); -- -- return iso_sched; --} -- --static inline void itd_sched_init(struct fotg210_hcd *fotg210, -- struct fotg210_iso_sched *iso_sched, -- struct fotg210_iso_stream *stream, struct urb *urb) --{ -- unsigned i; -- dma_addr_t dma = urb->transfer_dma; -- -- /* how many uframes are needed for these transfers */ -- iso_sched->span = urb->number_of_packets * stream->interval; -- -- /* figure out per-uframe itd fields that we'll need later -- * when we fit new itds into the schedule. -- */ -- for (i = 0; i < urb->number_of_packets; i++) { -- struct fotg210_iso_packet *uframe = &iso_sched->packet[i]; -- unsigned length; -- dma_addr_t buf; -- u32 trans; -- -- length = urb->iso_frame_desc[i].length; -- buf = dma + urb->iso_frame_desc[i].offset; -- -- trans = FOTG210_ISOC_ACTIVE; -- trans |= buf & 0x0fff; -- if (unlikely(((i + 1) == urb->number_of_packets)) -- && !(urb->transfer_flags & URB_NO_INTERRUPT)) -- trans |= FOTG210_ITD_IOC; -- trans |= length << 16; -- uframe->transaction = cpu_to_hc32(fotg210, trans); -- -- /* might need to cross a buffer page within a uframe */ -- uframe->bufp = (buf & ~(u64)0x0fff); -- buf += length; -- if (unlikely((uframe->bufp != (buf & ~(u64)0x0fff)))) -- uframe->cross = 1; -- } --} -- --static void iso_sched_free(struct fotg210_iso_stream *stream, -- struct fotg210_iso_sched *iso_sched) --{ -- if (!iso_sched) -- return; -- /* caller must hold fotg210->lock!*/ -- list_splice(&iso_sched->td_list, &stream->free_list); -- kfree(iso_sched); --} -- --static int itd_urb_transaction(struct fotg210_iso_stream *stream, -- struct fotg210_hcd *fotg210, struct urb *urb, gfp_t mem_flags) --{ -- struct fotg210_itd *itd; -- dma_addr_t itd_dma; -- int i; -- unsigned num_itds; -- struct fotg210_iso_sched *sched; -- unsigned long flags; -- -- sched = iso_sched_alloc(urb->number_of_packets, mem_flags); -- if (unlikely(sched == NULL)) -- return -ENOMEM; -- -- itd_sched_init(fotg210, sched, stream, urb); -- -- if (urb->interval < 8) -- num_itds = 1 + (sched->span + 7) / 8; -- else -- num_itds = urb->number_of_packets; -- -- /* allocate/init ITDs */ -- spin_lock_irqsave(&fotg210->lock, flags); -- for (i = 0; i < num_itds; i++) { -- -- /* -- * Use iTDs from the free list, but not iTDs that may -- * still be in use by the hardware. -- */ -- if (likely(!list_empty(&stream->free_list))) { -- itd = list_first_entry(&stream->free_list, -- struct fotg210_itd, itd_list); -- if (itd->frame == fotg210->now_frame) -- goto alloc_itd; -- list_del(&itd->itd_list); -- itd_dma = itd->itd_dma; -- } else { --alloc_itd: -- spin_unlock_irqrestore(&fotg210->lock, flags); -- itd = dma_pool_alloc(fotg210->itd_pool, mem_flags, -- &itd_dma); -- spin_lock_irqsave(&fotg210->lock, flags); -- if (!itd) { -- iso_sched_free(stream, sched); -- spin_unlock_irqrestore(&fotg210->lock, flags); -- return -ENOMEM; -- } -- } -- -- memset(itd, 0, sizeof(*itd)); -- itd->itd_dma = itd_dma; -- list_add(&itd->itd_list, &sched->td_list); -- } -- spin_unlock_irqrestore(&fotg210->lock, flags); -- -- /* temporarily store schedule info in hcpriv */ -- urb->hcpriv = sched; -- urb->error_count = 0; -- return 0; --} -- --static inline int itd_slot_ok(struct fotg210_hcd *fotg210, u32 mod, u32 uframe, -- u8 usecs, u32 period) --{ -- uframe %= period; -- do { -- /* can't commit more than uframe_periodic_max usec */ -- if (periodic_usecs(fotg210, uframe >> 3, uframe & 0x7) -- > (fotg210->uframe_periodic_max - usecs)) -- return 0; -- -- /* we know urb->interval is 2^N uframes */ -- uframe += period; -- } while (uframe < mod); -- return 1; --} -- --/* This scheduler plans almost as far into the future as it has actual -- * periodic schedule slots. (Affected by TUNE_FLS, which defaults to -- * "as small as possible" to be cache-friendlier.) That limits the size -- * transfers you can stream reliably; avoid more than 64 msec per urb. -- * Also avoid queue depths of less than fotg210's worst irq latency (affected -- * by the per-urb URB_NO_INTERRUPT hint, the log2_irq_thresh module parameter, -- * and other factors); or more than about 230 msec total (for portability, -- * given FOTG210_TUNE_FLS and the slop). Or, write a smarter scheduler! -- */ -- --#define SCHEDULE_SLOP 80 /* microframes */ -- --static int iso_stream_schedule(struct fotg210_hcd *fotg210, struct urb *urb, -- struct fotg210_iso_stream *stream) --{ -- u32 now, next, start, period, span; -- int status; -- unsigned mod = fotg210->periodic_size << 3; -- struct fotg210_iso_sched *sched = urb->hcpriv; -- -- period = urb->interval; -- span = sched->span; -- -- if (span > mod - SCHEDULE_SLOP) { -- fotg210_dbg(fotg210, "iso request %p too long\n", urb); -- status = -EFBIG; -- goto fail; -- } -- -- now = fotg210_read_frame_index(fotg210) & (mod - 1); -- -- /* Typical case: reuse current schedule, stream is still active. -- * Hopefully there are no gaps from the host falling behind -- * (irq delays etc), but if there are we'll take the next -- * slot in the schedule, implicitly assuming URB_ISO_ASAP. -- */ -- if (likely(!list_empty(&stream->td_list))) { -- u32 excess; -- -- /* For high speed devices, allow scheduling within the -- * isochronous scheduling threshold. For full speed devices -- * and Intel PCI-based controllers, don't (work around for -- * Intel ICH9 bug). -- */ -- if (!stream->highspeed && fotg210->fs_i_thresh) -- next = now + fotg210->i_thresh; -- else -- next = now; -- -- /* Fell behind (by up to twice the slop amount)? -- * We decide based on the time of the last currently-scheduled -- * slot, not the time of the next available slot. -- */ -- excess = (stream->next_uframe - period - next) & (mod - 1); -- if (excess >= mod - 2 * SCHEDULE_SLOP) -- start = next + excess - mod + period * -- DIV_ROUND_UP(mod - excess, period); -- else -- start = next + excess + period; -- if (start - now >= mod) { -- fotg210_dbg(fotg210, "request %p would overflow (%d+%d >= %d)\n", -- urb, start - now - period, period, -- mod); -- status = -EFBIG; -- goto fail; -- } -- } -- -- /* need to schedule; when's the next (u)frame we could start? -- * this is bigger than fotg210->i_thresh allows; scheduling itself -- * isn't free, the slop should handle reasonably slow cpus. it -- * can also help high bandwidth if the dma and irq loads don't -- * jump until after the queue is primed. -- */ -- else { -- int done = 0; -- -- start = SCHEDULE_SLOP + (now & ~0x07); -- -- /* NOTE: assumes URB_ISO_ASAP, to limit complexity/bugs */ -- -- /* find a uframe slot with enough bandwidth. -- * Early uframes are more precious because full-speed -- * iso IN transfers can't use late uframes, -- * and therefore they should be allocated last. -- */ -- next = start; -- start += period; -- do { -- start--; -- /* check schedule: enough space? */ -- if (itd_slot_ok(fotg210, mod, start, -- stream->usecs, period)) -- done = 1; -- } while (start > next && !done); -- -- /* no room in the schedule */ -- if (!done) { -- fotg210_dbg(fotg210, "iso resched full %p (now %d max %d)\n", -- urb, now, now + mod); -- status = -ENOSPC; -- goto fail; -- } -- } -- -- /* Tried to schedule too far into the future? */ -- if (unlikely(start - now + span - period >= -- mod - 2 * SCHEDULE_SLOP)) { -- fotg210_dbg(fotg210, "request %p would overflow (%d+%d >= %d)\n", -- urb, start - now, span - period, -- mod - 2 * SCHEDULE_SLOP); -- status = -EFBIG; -- goto fail; -- } -- -- stream->next_uframe = start & (mod - 1); -- -- /* report high speed start in uframes; full speed, in frames */ -- urb->start_frame = stream->next_uframe; -- if (!stream->highspeed) -- urb->start_frame >>= 3; -- -- /* Make sure scan_isoc() sees these */ -- if (fotg210->isoc_count == 0) -- fotg210->next_frame = now >> 3; -- return 0; -- --fail: -- iso_sched_free(stream, sched); -- urb->hcpriv = NULL; -- return status; --} -- --static inline void itd_init(struct fotg210_hcd *fotg210, -- struct fotg210_iso_stream *stream, struct fotg210_itd *itd) --{ -- int i; -- -- /* it's been recently zeroed */ -- itd->hw_next = FOTG210_LIST_END(fotg210); -- itd->hw_bufp[0] = stream->buf0; -- itd->hw_bufp[1] = stream->buf1; -- itd->hw_bufp[2] = stream->buf2; -- -- for (i = 0; i < 8; i++) -- itd->index[i] = -1; -- -- /* All other fields are filled when scheduling */ --} -- --static inline void itd_patch(struct fotg210_hcd *fotg210, -- struct fotg210_itd *itd, struct fotg210_iso_sched *iso_sched, -- unsigned index, u16 uframe) --{ -- struct fotg210_iso_packet *uf = &iso_sched->packet[index]; -- unsigned pg = itd->pg; -- -- uframe &= 0x07; -- itd->index[uframe] = index; -- -- itd->hw_transaction[uframe] = uf->transaction; -- itd->hw_transaction[uframe] |= cpu_to_hc32(fotg210, pg << 12); -- itd->hw_bufp[pg] |= cpu_to_hc32(fotg210, uf->bufp & ~(u32)0); -- itd->hw_bufp_hi[pg] |= cpu_to_hc32(fotg210, (u32)(uf->bufp >> 32)); -- -- /* iso_frame_desc[].offset must be strictly increasing */ -- if (unlikely(uf->cross)) { -- u64 bufp = uf->bufp + 4096; -- -- itd->pg = ++pg; -- itd->hw_bufp[pg] |= cpu_to_hc32(fotg210, bufp & ~(u32)0); -- itd->hw_bufp_hi[pg] |= cpu_to_hc32(fotg210, (u32)(bufp >> 32)); -- } --} -- --static inline void itd_link(struct fotg210_hcd *fotg210, unsigned frame, -- struct fotg210_itd *itd) --{ -- union fotg210_shadow *prev = &fotg210->pshadow[frame]; -- __hc32 *hw_p = &fotg210->periodic[frame]; -- union fotg210_shadow here = *prev; -- __hc32 type = 0; -- -- /* skip any iso nodes which might belong to previous microframes */ -- while (here.ptr) { -- type = Q_NEXT_TYPE(fotg210, *hw_p); -- if (type == cpu_to_hc32(fotg210, Q_TYPE_QH)) -- break; -- prev = periodic_next_shadow(fotg210, prev, type); -- hw_p = shadow_next_periodic(fotg210, &here, type); -- here = *prev; -- } -- -- itd->itd_next = here; -- itd->hw_next = *hw_p; -- prev->itd = itd; -- itd->frame = frame; -- wmb(); -- *hw_p = cpu_to_hc32(fotg210, itd->itd_dma | Q_TYPE_ITD); --} -- --/* fit urb's itds into the selected schedule slot; activate as needed */ --static void itd_link_urb(struct fotg210_hcd *fotg210, struct urb *urb, -- unsigned mod, struct fotg210_iso_stream *stream) --{ -- int packet; -- unsigned next_uframe, uframe, frame; -- struct fotg210_iso_sched *iso_sched = urb->hcpriv; -- struct fotg210_itd *itd; -- -- next_uframe = stream->next_uframe & (mod - 1); -- -- if (unlikely(list_empty(&stream->td_list))) { -- fotg210_to_hcd(fotg210)->self.bandwidth_allocated -- += stream->bandwidth; -- fotg210_dbg(fotg210, -- "schedule devp %s ep%d%s-iso period %d start %d.%d\n", -- urb->dev->devpath, stream->bEndpointAddress & 0x0f, -- (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out", -- urb->interval, -- next_uframe >> 3, next_uframe & 0x7); -- } -- -- /* fill iTDs uframe by uframe */ -- for (packet = 0, itd = NULL; packet < urb->number_of_packets;) { -- if (itd == NULL) { -- /* ASSERT: we have all necessary itds */ -- -- /* ASSERT: no itds for this endpoint in this uframe */ -- -- itd = list_entry(iso_sched->td_list.next, -- struct fotg210_itd, itd_list); -- list_move_tail(&itd->itd_list, &stream->td_list); -- itd->stream = stream; -- itd->urb = urb; -- itd_init(fotg210, stream, itd); -- } -- -- uframe = next_uframe & 0x07; -- frame = next_uframe >> 3; -- -- itd_patch(fotg210, itd, iso_sched, packet, uframe); -- -- next_uframe += stream->interval; -- next_uframe &= mod - 1; -- packet++; -- -- /* link completed itds into the schedule */ -- if (((next_uframe >> 3) != frame) -- || packet == urb->number_of_packets) { -- itd_link(fotg210, frame & (fotg210->periodic_size - 1), -- itd); -- itd = NULL; -- } -- } -- stream->next_uframe = next_uframe; -- -- /* don't need that schedule data any more */ -- iso_sched_free(stream, iso_sched); -- urb->hcpriv = NULL; -- -- ++fotg210->isoc_count; -- enable_periodic(fotg210); --} -- --#define ISO_ERRS (FOTG210_ISOC_BUF_ERR | FOTG210_ISOC_BABBLE |\ -- FOTG210_ISOC_XACTERR) -- --/* Process and recycle a completed ITD. Return true iff its urb completed, -- * and hence its completion callback probably added things to the hardware -- * schedule. -- * -- * Note that we carefully avoid recycling this descriptor until after any -- * completion callback runs, so that it won't be reused quickly. That is, -- * assuming (a) no more than two urbs per frame on this endpoint, and also -- * (b) only this endpoint's completions submit URBs. It seems some silicon -- * corrupts things if you reuse completed descriptors very quickly... -- */ --static bool itd_complete(struct fotg210_hcd *fotg210, struct fotg210_itd *itd) --{ -- struct urb *urb = itd->urb; -- struct usb_iso_packet_descriptor *desc; -- u32 t; -- unsigned uframe; -- int urb_index = -1; -- struct fotg210_iso_stream *stream = itd->stream; -- struct usb_device *dev; -- bool retval = false; -- -- /* for each uframe with a packet */ -- for (uframe = 0; uframe < 8; uframe++) { -- if (likely(itd->index[uframe] == -1)) -- continue; -- urb_index = itd->index[uframe]; -- desc = &urb->iso_frame_desc[urb_index]; -- -- t = hc32_to_cpup(fotg210, &itd->hw_transaction[uframe]); -- itd->hw_transaction[uframe] = 0; -- -- /* report transfer status */ -- if (unlikely(t & ISO_ERRS)) { -- urb->error_count++; -- if (t & FOTG210_ISOC_BUF_ERR) -- desc->status = usb_pipein(urb->pipe) -- ? -ENOSR /* hc couldn't read */ -- : -ECOMM; /* hc couldn't write */ -- else if (t & FOTG210_ISOC_BABBLE) -- desc->status = -EOVERFLOW; -- else /* (t & FOTG210_ISOC_XACTERR) */ -- desc->status = -EPROTO; -- -- /* HC need not update length with this error */ -- if (!(t & FOTG210_ISOC_BABBLE)) { -- desc->actual_length = FOTG210_ITD_LENGTH(t); -- urb->actual_length += desc->actual_length; -- } -- } else if (likely((t & FOTG210_ISOC_ACTIVE) == 0)) { -- desc->status = 0; -- desc->actual_length = FOTG210_ITD_LENGTH(t); -- urb->actual_length += desc->actual_length; -- } else { -- /* URB was too late */ -- desc->status = -EXDEV; -- } -- } -- -- /* handle completion now? */ -- if (likely((urb_index + 1) != urb->number_of_packets)) -- goto done; -- -- /* ASSERT: it's really the last itd for this urb -- * list_for_each_entry (itd, &stream->td_list, itd_list) -- * BUG_ON (itd->urb == urb); -- */ -- -- /* give urb back to the driver; completion often (re)submits */ -- dev = urb->dev; -- fotg210_urb_done(fotg210, urb, 0); -- retval = true; -- urb = NULL; -- -- --fotg210->isoc_count; -- disable_periodic(fotg210); -- -- if (unlikely(list_is_singular(&stream->td_list))) { -- fotg210_to_hcd(fotg210)->self.bandwidth_allocated -- -= stream->bandwidth; -- fotg210_dbg(fotg210, -- "deschedule devp %s ep%d%s-iso\n", -- dev->devpath, stream->bEndpointAddress & 0x0f, -- (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out"); -- } -- --done: -- itd->urb = NULL; -- -- /* Add to the end of the free list for later reuse */ -- list_move_tail(&itd->itd_list, &stream->free_list); -- -- /* Recycle the iTDs when the pipeline is empty (ep no longer in use) */ -- if (list_empty(&stream->td_list)) { -- list_splice_tail_init(&stream->free_list, -- &fotg210->cached_itd_list); -- start_free_itds(fotg210); -- } -- -- return retval; --} -- --static int itd_submit(struct fotg210_hcd *fotg210, struct urb *urb, -- gfp_t mem_flags) --{ -- int status = -EINVAL; -- unsigned long flags; -- struct fotg210_iso_stream *stream; -- -- /* Get iso_stream head */ -- stream = iso_stream_find(fotg210, urb); -- if (unlikely(stream == NULL)) { -- fotg210_dbg(fotg210, "can't get iso stream\n"); -- return -ENOMEM; -- } -- if (unlikely(urb->interval != stream->interval && -- fotg210_port_speed(fotg210, 0) == -- USB_PORT_STAT_HIGH_SPEED)) { -- fotg210_dbg(fotg210, "can't change iso interval %d --> %d\n", -- stream->interval, urb->interval); -- goto done; -- } -- --#ifdef FOTG210_URB_TRACE -- fotg210_dbg(fotg210, -- "%s %s urb %p ep%d%s len %d, %d pkts %d uframes[%p]\n", -- __func__, urb->dev->devpath, urb, -- usb_pipeendpoint(urb->pipe), -- usb_pipein(urb->pipe) ? "in" : "out", -- urb->transfer_buffer_length, -- urb->number_of_packets, urb->interval, -- stream); --#endif -- -- /* allocate ITDs w/o locking anything */ -- status = itd_urb_transaction(stream, fotg210, urb, mem_flags); -- if (unlikely(status < 0)) { -- fotg210_dbg(fotg210, "can't init itds\n"); -- goto done; -- } -- -- /* schedule ... need to lock */ -- spin_lock_irqsave(&fotg210->lock, flags); -- if (unlikely(!HCD_HW_ACCESSIBLE(fotg210_to_hcd(fotg210)))) { -- status = -ESHUTDOWN; -- goto done_not_linked; -- } -- status = usb_hcd_link_urb_to_ep(fotg210_to_hcd(fotg210), urb); -- if (unlikely(status)) -- goto done_not_linked; -- status = iso_stream_schedule(fotg210, urb, stream); -- if (likely(status == 0)) -- itd_link_urb(fotg210, urb, fotg210->periodic_size << 3, stream); -- else -- usb_hcd_unlink_urb_from_ep(fotg210_to_hcd(fotg210), urb); --done_not_linked: -- spin_unlock_irqrestore(&fotg210->lock, flags); --done: -- return status; --} -- --static inline int scan_frame_queue(struct fotg210_hcd *fotg210, unsigned frame, -- unsigned now_frame, bool live) --{ -- unsigned uf; -- bool modified; -- union fotg210_shadow q, *q_p; -- __hc32 type, *hw_p; -- -- /* scan each element in frame's queue for completions */ -- q_p = &fotg210->pshadow[frame]; -- hw_p = &fotg210->periodic[frame]; -- q.ptr = q_p->ptr; -- type = Q_NEXT_TYPE(fotg210, *hw_p); -- modified = false; -- -- while (q.ptr) { -- switch (hc32_to_cpu(fotg210, type)) { -- case Q_TYPE_ITD: -- /* If this ITD is still active, leave it for -- * later processing ... check the next entry. -- * No need to check for activity unless the -- * frame is current. -- */ -- if (frame == now_frame && live) { -- rmb(); -- for (uf = 0; uf < 8; uf++) { -- if (q.itd->hw_transaction[uf] & -- ITD_ACTIVE(fotg210)) -- break; -- } -- if (uf < 8) { -- q_p = &q.itd->itd_next; -- hw_p = &q.itd->hw_next; -- type = Q_NEXT_TYPE(fotg210, -- q.itd->hw_next); -- q = *q_p; -- break; -- } -- } -- -- /* Take finished ITDs out of the schedule -- * and process them: recycle, maybe report -- * URB completion. HC won't cache the -- * pointer for much longer, if at all. -- */ -- *q_p = q.itd->itd_next; -- *hw_p = q.itd->hw_next; -- type = Q_NEXT_TYPE(fotg210, q.itd->hw_next); -- wmb(); -- modified = itd_complete(fotg210, q.itd); -- q = *q_p; -- break; -- default: -- fotg210_dbg(fotg210, "corrupt type %d frame %d shadow %p\n", -- type, frame, q.ptr); -- fallthrough; -- case Q_TYPE_QH: -- case Q_TYPE_FSTN: -- /* End of the iTDs and siTDs */ -- q.ptr = NULL; -- break; -- } -- -- /* assume completion callbacks modify the queue */ -- if (unlikely(modified && fotg210->isoc_count > 0)) -- return -EINVAL; -- } -- return 0; --} -- --static void scan_isoc(struct fotg210_hcd *fotg210) --{ -- unsigned uf, now_frame, frame, ret; -- unsigned fmask = fotg210->periodic_size - 1; -- bool live; -- -- /* -- * When running, scan from last scan point up to "now" -- * else clean up by scanning everything that's left. -- * Touches as few pages as possible: cache-friendly. -- */ -- if (fotg210->rh_state >= FOTG210_RH_RUNNING) { -- uf = fotg210_read_frame_index(fotg210); -- now_frame = (uf >> 3) & fmask; -- live = true; -- } else { -- now_frame = (fotg210->next_frame - 1) & fmask; -- live = false; -- } -- fotg210->now_frame = now_frame; -- -- frame = fotg210->next_frame; -- for (;;) { -- ret = 1; -- while (ret != 0) -- ret = scan_frame_queue(fotg210, frame, -- now_frame, live); -- -- /* Stop when we have reached the current frame */ -- if (frame == now_frame) -- break; -- frame = (frame + 1) & fmask; -- } -- fotg210->next_frame = now_frame; --} -- --/* Display / Set uframe_periodic_max -- */ --static ssize_t uframe_periodic_max_show(struct device *dev, -- struct device_attribute *attr, char *buf) --{ -- struct fotg210_hcd *fotg210; -- int n; -- -- fotg210 = hcd_to_fotg210(bus_to_hcd(dev_get_drvdata(dev))); -- n = scnprintf(buf, PAGE_SIZE, "%d\n", fotg210->uframe_periodic_max); -- return n; --} -- -- --static ssize_t uframe_periodic_max_store(struct device *dev, -- struct device_attribute *attr, const char *buf, size_t count) --{ -- struct fotg210_hcd *fotg210; -- unsigned uframe_periodic_max; -- unsigned frame, uframe; -- unsigned short allocated_max; -- unsigned long flags; -- ssize_t ret; -- -- fotg210 = hcd_to_fotg210(bus_to_hcd(dev_get_drvdata(dev))); -- if (kstrtouint(buf, 0, &uframe_periodic_max) < 0) -- return -EINVAL; -- -- if (uframe_periodic_max < 100 || uframe_periodic_max >= 125) { -- fotg210_info(fotg210, "rejecting invalid request for uframe_periodic_max=%u\n", -- uframe_periodic_max); -- return -EINVAL; -- } -- -- ret = -EINVAL; -- -- /* -- * lock, so that our checking does not race with possible periodic -- * bandwidth allocation through submitting new urbs. -- */ -- spin_lock_irqsave(&fotg210->lock, flags); -- -- /* -- * for request to decrease max periodic bandwidth, we have to check -- * every microframe in the schedule to see whether the decrease is -- * possible. -- */ -- if (uframe_periodic_max < fotg210->uframe_periodic_max) { -- allocated_max = 0; -- -- for (frame = 0; frame < fotg210->periodic_size; ++frame) -- for (uframe = 0; uframe < 7; ++uframe) -- allocated_max = max(allocated_max, -- periodic_usecs(fotg210, frame, -- uframe)); -- -- if (allocated_max > uframe_periodic_max) { -- fotg210_info(fotg210, -- "cannot decrease uframe_periodic_max because periodic bandwidth is already allocated (%u > %u)\n", -- allocated_max, uframe_periodic_max); -- goto out_unlock; -- } -- } -- -- /* increasing is always ok */ -- -- fotg210_info(fotg210, -- "setting max periodic bandwidth to %u%% (== %u usec/uframe)\n", -- 100 * uframe_periodic_max/125, uframe_periodic_max); -- -- if (uframe_periodic_max != 100) -- fotg210_warn(fotg210, "max periodic bandwidth set is non-standard\n"); -- -- fotg210->uframe_periodic_max = uframe_periodic_max; -- ret = count; -- --out_unlock: -- spin_unlock_irqrestore(&fotg210->lock, flags); -- return ret; --} -- --static DEVICE_ATTR_RW(uframe_periodic_max); -- --static inline int create_sysfs_files(struct fotg210_hcd *fotg210) --{ -- struct device *controller = fotg210_to_hcd(fotg210)->self.controller; -- -- return device_create_file(controller, &dev_attr_uframe_periodic_max); --} -- --static inline void remove_sysfs_files(struct fotg210_hcd *fotg210) --{ -- struct device *controller = fotg210_to_hcd(fotg210)->self.controller; -- -- device_remove_file(controller, &dev_attr_uframe_periodic_max); --} --/* On some systems, leaving remote wakeup enabled prevents system shutdown. -- * The firmware seems to think that powering off is a wakeup event! -- * This routine turns off remote wakeup and everything else, on all ports. -- */ --static void fotg210_turn_off_all_ports(struct fotg210_hcd *fotg210) --{ -- u32 __iomem *status_reg = &fotg210->regs->port_status; -- -- fotg210_writel(fotg210, PORT_RWC_BITS, status_reg); --} -- --/* Halt HC, turn off all ports, and let the BIOS use the companion controllers. -- * Must be called with interrupts enabled and the lock not held. -- */ --static void fotg210_silence_controller(struct fotg210_hcd *fotg210) --{ -- fotg210_halt(fotg210); -- -- spin_lock_irq(&fotg210->lock); -- fotg210->rh_state = FOTG210_RH_HALTED; -- fotg210_turn_off_all_ports(fotg210); -- spin_unlock_irq(&fotg210->lock); --} -- --/* fotg210_shutdown kick in for silicon on any bus (not just pci, etc). -- * This forcibly disables dma and IRQs, helping kexec and other cases -- * where the next system software may expect clean state. -- */ --static void fotg210_shutdown(struct usb_hcd *hcd) --{ -- struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); -- -- spin_lock_irq(&fotg210->lock); -- fotg210->shutdown = true; -- fotg210->rh_state = FOTG210_RH_STOPPING; -- fotg210->enabled_hrtimer_events = 0; -- spin_unlock_irq(&fotg210->lock); -- -- fotg210_silence_controller(fotg210); -- -- hrtimer_cancel(&fotg210->hrtimer); --} -- --/* fotg210_work is called from some interrupts, timers, and so on. -- * it calls driver completion functions, after dropping fotg210->lock. -- */ --static void fotg210_work(struct fotg210_hcd *fotg210) --{ -- /* another CPU may drop fotg210->lock during a schedule scan while -- * it reports urb completions. this flag guards against bogus -- * attempts at re-entrant schedule scanning. -- */ -- if (fotg210->scanning) { -- fotg210->need_rescan = true; -- return; -- } -- fotg210->scanning = true; -- --rescan: -- fotg210->need_rescan = false; -- if (fotg210->async_count) -- scan_async(fotg210); -- if (fotg210->intr_count > 0) -- scan_intr(fotg210); -- if (fotg210->isoc_count > 0) -- scan_isoc(fotg210); -- if (fotg210->need_rescan) -- goto rescan; -- fotg210->scanning = false; -- -- /* the IO watchdog guards against hardware or driver bugs that -- * misplace IRQs, and should let us run completely without IRQs. -- * such lossage has been observed on both VT6202 and VT8235. -- */ -- turn_on_io_watchdog(fotg210); --} -- --/* Called when the fotg210_hcd module is removed. -- */ --static void fotg210_stop(struct usb_hcd *hcd) --{ -- struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); -- -- fotg210_dbg(fotg210, "stop\n"); -- -- /* no more interrupts ... */ -- -- spin_lock_irq(&fotg210->lock); -- fotg210->enabled_hrtimer_events = 0; -- spin_unlock_irq(&fotg210->lock); -- -- fotg210_quiesce(fotg210); -- fotg210_silence_controller(fotg210); -- fotg210_reset(fotg210); -- -- hrtimer_cancel(&fotg210->hrtimer); -- remove_sysfs_files(fotg210); -- remove_debug_files(fotg210); -- -- /* root hub is shut down separately (first, when possible) */ -- spin_lock_irq(&fotg210->lock); -- end_free_itds(fotg210); -- spin_unlock_irq(&fotg210->lock); -- fotg210_mem_cleanup(fotg210); -- --#ifdef FOTG210_STATS -- fotg210_dbg(fotg210, "irq normal %ld err %ld iaa %ld (lost %ld)\n", -- fotg210->stats.normal, fotg210->stats.error, -- fotg210->stats.iaa, fotg210->stats.lost_iaa); -- fotg210_dbg(fotg210, "complete %ld unlink %ld\n", -- fotg210->stats.complete, fotg210->stats.unlink); --#endif -- -- dbg_status(fotg210, "fotg210_stop completed", -- fotg210_readl(fotg210, &fotg210->regs->status)); --} -- --/* one-time init, only for memory state */ --static int hcd_fotg210_init(struct usb_hcd *hcd) --{ -- struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); -- u32 temp; -- int retval; -- u32 hcc_params; -- struct fotg210_qh_hw *hw; -- -- spin_lock_init(&fotg210->lock); -- -- /* -- * keep io watchdog by default, those good HCDs could turn off it later -- */ -- fotg210->need_io_watchdog = 1; -- -- hrtimer_init(&fotg210->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); -- fotg210->hrtimer.function = fotg210_hrtimer_func; -- fotg210->next_hrtimer_event = FOTG210_HRTIMER_NO_EVENT; -- -- hcc_params = fotg210_readl(fotg210, &fotg210->caps->hcc_params); -- -- /* -- * by default set standard 80% (== 100 usec/uframe) max periodic -- * bandwidth as required by USB 2.0 -- */ -- fotg210->uframe_periodic_max = 100; -- -- /* -- * hw default: 1K periodic list heads, one per frame. -- * periodic_size can shrink by USBCMD update if hcc_params allows. -- */ -- fotg210->periodic_size = DEFAULT_I_TDPS; -- INIT_LIST_HEAD(&fotg210->intr_qh_list); -- INIT_LIST_HEAD(&fotg210->cached_itd_list); -- -- if (HCC_PGM_FRAMELISTLEN(hcc_params)) { -- /* periodic schedule size can be smaller than default */ -- switch (FOTG210_TUNE_FLS) { -- case 0: -- fotg210->periodic_size = 1024; -- break; -- case 1: -- fotg210->periodic_size = 512; -- break; -- case 2: -- fotg210->periodic_size = 256; -- break; -- default: -- BUG(); -- } -- } -- retval = fotg210_mem_init(fotg210, GFP_KERNEL); -- if (retval < 0) -- return retval; -- -- /* controllers may cache some of the periodic schedule ... */ -- fotg210->i_thresh = 2; -- -- /* -- * dedicate a qh for the async ring head, since we couldn't unlink -- * a 'real' qh without stopping the async schedule [4.8]. use it -- * as the 'reclamation list head' too. -- * its dummy is used in hw_alt_next of many tds, to prevent the qh -- * from automatically advancing to the next td after short reads. -- */ -- fotg210->async->qh_next.qh = NULL; -- hw = fotg210->async->hw; -- hw->hw_next = QH_NEXT(fotg210, fotg210->async->qh_dma); -- hw->hw_info1 = cpu_to_hc32(fotg210, QH_HEAD); -- hw->hw_token = cpu_to_hc32(fotg210, QTD_STS_HALT); -- hw->hw_qtd_next = FOTG210_LIST_END(fotg210); -- fotg210->async->qh_state = QH_STATE_LINKED; -- hw->hw_alt_next = QTD_NEXT(fotg210, fotg210->async->dummy->qtd_dma); -- -- /* clear interrupt enables, set irq latency */ -- if (log2_irq_thresh < 0 || log2_irq_thresh > 6) -- log2_irq_thresh = 0; -- temp = 1 << (16 + log2_irq_thresh); -- if (HCC_CANPARK(hcc_params)) { -- /* HW default park == 3, on hardware that supports it (like -- * NVidia and ALI silicon), maximizes throughput on the async -- * schedule by avoiding QH fetches between transfers. -- * -- * With fast usb storage devices and NForce2, "park" seems to -- * make problems: throughput reduction (!), data errors... -- */ -- if (park) { -- park = min_t(unsigned, park, 3); -- temp |= CMD_PARK; -- temp |= park << 8; -- } -- fotg210_dbg(fotg210, "park %d\n", park); -- } -- if (HCC_PGM_FRAMELISTLEN(hcc_params)) { -- /* periodic schedule size can be smaller than default */ -- temp &= ~(3 << 2); -- temp |= (FOTG210_TUNE_FLS << 2); -- } -- fotg210->command = temp; -- -- /* Accept arbitrarily long scatter-gather lists */ -- if (!hcd->localmem_pool) -- hcd->self.sg_tablesize = ~0; -- return 0; --} -- --/* start HC running; it's halted, hcd_fotg210_init() has been run (once) */ --static int fotg210_run(struct usb_hcd *hcd) --{ -- struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); -- u32 temp; -- -- hcd->uses_new_polling = 1; -- -- /* EHCI spec section 4.1 */ -- -- fotg210_writel(fotg210, fotg210->periodic_dma, -- &fotg210->regs->frame_list); -- fotg210_writel(fotg210, (u32)fotg210->async->qh_dma, -- &fotg210->regs->async_next); -- -- /* -- * hcc_params controls whether fotg210->regs->segment must (!!!) -- * be used; it constrains QH/ITD/SITD and QTD locations. -- * dma_pool consistent memory always uses segment zero. -- * streaming mappings for I/O buffers, like dma_map_single(), -- * can return segments above 4GB, if the device allows. -- * -- * NOTE: the dma mask is visible through dev->dma_mask, so -- * drivers can pass this info along ... like NETIF_F_HIGHDMA, -- * Scsi_Host.highmem_io, and so forth. It's readonly to all -- * host side drivers though. -- */ -- fotg210_readl(fotg210, &fotg210->caps->hcc_params); -- -- /* -- * Philips, Intel, and maybe others need CMD_RUN before the -- * root hub will detect new devices (why?); NEC doesn't -- */ -- fotg210->command &= ~(CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET); -- fotg210->command |= CMD_RUN; -- fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command); -- dbg_cmd(fotg210, "init", fotg210->command); -- -- /* -- * Start, enabling full USB 2.0 functionality ... usb 1.1 devices -- * are explicitly handed to companion controller(s), so no TT is -- * involved with the root hub. (Except where one is integrated, -- * and there's no companion controller unless maybe for USB OTG.) -- * -- * Turning on the CF flag will transfer ownership of all ports -- * from the companions to the EHCI controller. If any of the -- * companions are in the middle of a port reset at the time, it -- * could cause trouble. Write-locking ehci_cf_port_reset_rwsem -- * guarantees that no resets are in progress. After we set CF, -- * a short delay lets the hardware catch up; new resets shouldn't -- * be started before the port switching actions could complete. -- */ -- down_write(&ehci_cf_port_reset_rwsem); -- fotg210->rh_state = FOTG210_RH_RUNNING; -- /* unblock posted writes */ -- fotg210_readl(fotg210, &fotg210->regs->command); -- usleep_range(5000, 10000); -- up_write(&ehci_cf_port_reset_rwsem); -- fotg210->last_periodic_enable = ktime_get_real(); -- -- temp = HC_VERSION(fotg210, -- fotg210_readl(fotg210, &fotg210->caps->hc_capbase)); -- fotg210_info(fotg210, -- "USB %x.%x started, EHCI %x.%02x\n", -- ((fotg210->sbrn & 0xf0) >> 4), (fotg210->sbrn & 0x0f), -- temp >> 8, temp & 0xff); -- -- fotg210_writel(fotg210, INTR_MASK, -- &fotg210->regs->intr_enable); /* Turn On Interrupts */ -- -- /* GRR this is run-once init(), being done every time the HC starts. -- * So long as they're part of class devices, we can't do it init() -- * since the class device isn't created that early. -- */ -- create_debug_files(fotg210); -- create_sysfs_files(fotg210); -- -- return 0; --} -- --static int fotg210_setup(struct usb_hcd *hcd) --{ -- struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); -- int retval; -- -- fotg210->regs = (void __iomem *)fotg210->caps + -- HC_LENGTH(fotg210, -- fotg210_readl(fotg210, &fotg210->caps->hc_capbase)); -- dbg_hcs_params(fotg210, "reset"); -- dbg_hcc_params(fotg210, "reset"); -- -- /* cache this readonly data; minimize chip reads */ -- fotg210->hcs_params = fotg210_readl(fotg210, -- &fotg210->caps->hcs_params); -- -- fotg210->sbrn = HCD_USB2; -- -- /* data structure init */ -- retval = hcd_fotg210_init(hcd); -- if (retval) -- return retval; -- -- retval = fotg210_halt(fotg210); -- if (retval) -- return retval; -- -- fotg210_reset(fotg210); -- -- return 0; --} -- --static irqreturn_t fotg210_irq(struct usb_hcd *hcd) --{ -- struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); -- u32 status, masked_status, pcd_status = 0, cmd; -- int bh; -- -- spin_lock(&fotg210->lock); -- -- status = fotg210_readl(fotg210, &fotg210->regs->status); -- -- /* e.g. cardbus physical eject */ -- if (status == ~(u32) 0) { -- fotg210_dbg(fotg210, "device removed\n"); -- goto dead; -- } -- -- /* -- * We don't use STS_FLR, but some controllers don't like it to -- * remain on, so mask it out along with the other status bits. -- */ -- masked_status = status & (INTR_MASK | STS_FLR); -- -- /* Shared IRQ? */ -- if (!masked_status || -- unlikely(fotg210->rh_state == FOTG210_RH_HALTED)) { -- spin_unlock(&fotg210->lock); -- return IRQ_NONE; -- } -- -- /* clear (just) interrupts */ -- fotg210_writel(fotg210, masked_status, &fotg210->regs->status); -- cmd = fotg210_readl(fotg210, &fotg210->regs->command); -- bh = 0; -- -- /* unrequested/ignored: Frame List Rollover */ -- dbg_status(fotg210, "irq", status); -- -- /* INT, ERR, and IAA interrupt rates can be throttled */ -- -- /* normal [4.15.1.2] or error [4.15.1.1] completion */ -- if (likely((status & (STS_INT|STS_ERR)) != 0)) { -- if (likely((status & STS_ERR) == 0)) -- INCR(fotg210->stats.normal); -- else -- INCR(fotg210->stats.error); -- bh = 1; -- } -- -- /* complete the unlinking of some qh [4.15.2.3] */ -- if (status & STS_IAA) { -- -- /* Turn off the IAA watchdog */ -- fotg210->enabled_hrtimer_events &= -- ~BIT(FOTG210_HRTIMER_IAA_WATCHDOG); -- -- /* -- * Mild optimization: Allow another IAAD to reset the -- * hrtimer, if one occurs before the next expiration. -- * In theory we could always cancel the hrtimer, but -- * tests show that about half the time it will be reset -- * for some other event anyway. -- */ -- if (fotg210->next_hrtimer_event == FOTG210_HRTIMER_IAA_WATCHDOG) -- ++fotg210->next_hrtimer_event; -- -- /* guard against (alleged) silicon errata */ -- if (cmd & CMD_IAAD) -- fotg210_dbg(fotg210, "IAA with IAAD still set?\n"); -- if (fotg210->async_iaa) { -- INCR(fotg210->stats.iaa); -- end_unlink_async(fotg210); -- } else -- fotg210_dbg(fotg210, "IAA with nothing unlinked?\n"); -- } -- -- /* remote wakeup [4.3.1] */ -- if (status & STS_PCD) { -- int pstatus; -- u32 __iomem *status_reg = &fotg210->regs->port_status; -- -- /* kick root hub later */ -- pcd_status = status; -- -- /* resume root hub? */ -- if (fotg210->rh_state == FOTG210_RH_SUSPENDED) -- usb_hcd_resume_root_hub(hcd); -- -- pstatus = fotg210_readl(fotg210, status_reg); -- -- if (test_bit(0, &fotg210->suspended_ports) && -- ((pstatus & PORT_RESUME) || -- !(pstatus & PORT_SUSPEND)) && -- (pstatus & PORT_PE) && -- fotg210->reset_done[0] == 0) { -- -- /* start 20 msec resume signaling from this port, -- * and make hub_wq collect PORT_STAT_C_SUSPEND to -- * stop that signaling. Use 5 ms extra for safety, -- * like usb_port_resume() does. -- */ -- fotg210->reset_done[0] = jiffies + msecs_to_jiffies(25); -- set_bit(0, &fotg210->resuming_ports); -- fotg210_dbg(fotg210, "port 1 remote wakeup\n"); -- mod_timer(&hcd->rh_timer, fotg210->reset_done[0]); -- } -- } -- -- /* PCI errors [4.15.2.4] */ -- if (unlikely((status & STS_FATAL) != 0)) { -- fotg210_err(fotg210, "fatal error\n"); -- dbg_cmd(fotg210, "fatal", cmd); -- dbg_status(fotg210, "fatal", status); --dead: -- usb_hc_died(hcd); -- -- /* Don't let the controller do anything more */ -- fotg210->shutdown = true; -- fotg210->rh_state = FOTG210_RH_STOPPING; -- fotg210->command &= ~(CMD_RUN | CMD_ASE | CMD_PSE); -- fotg210_writel(fotg210, fotg210->command, -- &fotg210->regs->command); -- fotg210_writel(fotg210, 0, &fotg210->regs->intr_enable); -- fotg210_handle_controller_death(fotg210); -- -- /* Handle completions when the controller stops */ -- bh = 0; -- } -- -- if (bh) -- fotg210_work(fotg210); -- spin_unlock(&fotg210->lock); -- if (pcd_status) -- usb_hcd_poll_rh_status(hcd); -- return IRQ_HANDLED; --} -- --/* non-error returns are a promise to giveback() the urb later -- * we drop ownership so next owner (or urb unlink) can get it -- * -- * urb + dev is in hcd.self.controller.urb_list -- * we're queueing TDs onto software and hardware lists -- * -- * hcd-specific init for hcpriv hasn't been done yet -- * -- * NOTE: control, bulk, and interrupt share the same code to append TDs -- * to a (possibly active) QH, and the same QH scanning code. -- */ --static int fotg210_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, -- gfp_t mem_flags) --{ -- struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); -- struct list_head qtd_list; -- -- INIT_LIST_HEAD(&qtd_list); -- -- switch (usb_pipetype(urb->pipe)) { -- case PIPE_CONTROL: -- /* qh_completions() code doesn't handle all the fault cases -- * in multi-TD control transfers. Even 1KB is rare anyway. -- */ -- if (urb->transfer_buffer_length > (16 * 1024)) -- return -EMSGSIZE; -- fallthrough; -- /* case PIPE_BULK: */ -- default: -- if (!qh_urb_transaction(fotg210, urb, &qtd_list, mem_flags)) -- return -ENOMEM; -- return submit_async(fotg210, urb, &qtd_list, mem_flags); -- -- case PIPE_INTERRUPT: -- if (!qh_urb_transaction(fotg210, urb, &qtd_list, mem_flags)) -- return -ENOMEM; -- return intr_submit(fotg210, urb, &qtd_list, mem_flags); -- -- case PIPE_ISOCHRONOUS: -- return itd_submit(fotg210, urb, mem_flags); -- } --} -- --/* remove from hardware lists -- * completions normally happen asynchronously -- */ -- --static int fotg210_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) --{ -- struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); -- struct fotg210_qh *qh; -- unsigned long flags; -- int rc; -- -- spin_lock_irqsave(&fotg210->lock, flags); -- rc = usb_hcd_check_unlink_urb(hcd, urb, status); -- if (rc) -- goto done; -- -- switch (usb_pipetype(urb->pipe)) { -- /* case PIPE_CONTROL: */ -- /* case PIPE_BULK:*/ -- default: -- qh = (struct fotg210_qh *) urb->hcpriv; -- if (!qh) -- break; -- switch (qh->qh_state) { -- case QH_STATE_LINKED: -- case QH_STATE_COMPLETING: -- start_unlink_async(fotg210, qh); -- break; -- case QH_STATE_UNLINK: -- case QH_STATE_UNLINK_WAIT: -- /* already started */ -- break; -- case QH_STATE_IDLE: -- /* QH might be waiting for a Clear-TT-Buffer */ -- qh_completions(fotg210, qh); -- break; -- } -- break; -- -- case PIPE_INTERRUPT: -- qh = (struct fotg210_qh *) urb->hcpriv; -- if (!qh) -- break; -- switch (qh->qh_state) { -- case QH_STATE_LINKED: -- case QH_STATE_COMPLETING: -- start_unlink_intr(fotg210, qh); -- break; -- case QH_STATE_IDLE: -- qh_completions(fotg210, qh); -- break; -- default: -- fotg210_dbg(fotg210, "bogus qh %p state %d\n", -- qh, qh->qh_state); -- goto done; -- } -- break; -- -- case PIPE_ISOCHRONOUS: -- /* itd... */ -- -- /* wait till next completion, do it then. */ -- /* completion irqs can wait up to 1024 msec, */ -- break; -- } --done: -- spin_unlock_irqrestore(&fotg210->lock, flags); -- return rc; --} -- --/* bulk qh holds the data toggle */ -- --static void fotg210_endpoint_disable(struct usb_hcd *hcd, -- struct usb_host_endpoint *ep) --{ -- struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); -- unsigned long flags; -- struct fotg210_qh *qh, *tmp; -- -- /* ASSERT: any requests/urbs are being unlinked */ -- /* ASSERT: nobody can be submitting urbs for this any more */ -- --rescan: -- spin_lock_irqsave(&fotg210->lock, flags); -- qh = ep->hcpriv; -- if (!qh) -- goto done; -- -- /* endpoints can be iso streams. for now, we don't -- * accelerate iso completions ... so spin a while. -- */ -- if (qh->hw == NULL) { -- struct fotg210_iso_stream *stream = ep->hcpriv; -- -- if (!list_empty(&stream->td_list)) -- goto idle_timeout; -- -- /* BUG_ON(!list_empty(&stream->free_list)); */ -- kfree(stream); -- goto done; -- } -- -- if (fotg210->rh_state < FOTG210_RH_RUNNING) -- qh->qh_state = QH_STATE_IDLE; -- switch (qh->qh_state) { -- case QH_STATE_LINKED: -- case QH_STATE_COMPLETING: -- for (tmp = fotg210->async->qh_next.qh; -- tmp && tmp != qh; -- tmp = tmp->qh_next.qh) -- continue; -- /* periodic qh self-unlinks on empty, and a COMPLETING qh -- * may already be unlinked. -- */ -- if (tmp) -- start_unlink_async(fotg210, qh); -- fallthrough; -- case QH_STATE_UNLINK: /* wait for hw to finish? */ -- case QH_STATE_UNLINK_WAIT: --idle_timeout: -- spin_unlock_irqrestore(&fotg210->lock, flags); -- schedule_timeout_uninterruptible(1); -- goto rescan; -- case QH_STATE_IDLE: /* fully unlinked */ -- if (qh->clearing_tt) -- goto idle_timeout; -- if (list_empty(&qh->qtd_list)) { -- qh_destroy(fotg210, qh); -- break; -- } -- fallthrough; -- default: -- /* caller was supposed to have unlinked any requests; -- * that's not our job. just leak this memory. -- */ -- fotg210_err(fotg210, "qh %p (#%02x) state %d%s\n", -- qh, ep->desc.bEndpointAddress, qh->qh_state, -- list_empty(&qh->qtd_list) ? "" : "(has tds)"); -- break; -- } --done: -- ep->hcpriv = NULL; -- spin_unlock_irqrestore(&fotg210->lock, flags); --} -- --static void fotg210_endpoint_reset(struct usb_hcd *hcd, -- struct usb_host_endpoint *ep) --{ -- struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); -- struct fotg210_qh *qh; -- int eptype = usb_endpoint_type(&ep->desc); -- int epnum = usb_endpoint_num(&ep->desc); -- int is_out = usb_endpoint_dir_out(&ep->desc); -- unsigned long flags; -- -- if (eptype != USB_ENDPOINT_XFER_BULK && eptype != USB_ENDPOINT_XFER_INT) -- return; -- -- spin_lock_irqsave(&fotg210->lock, flags); -- qh = ep->hcpriv; -- -- /* For Bulk and Interrupt endpoints we maintain the toggle state -- * in the hardware; the toggle bits in udev aren't used at all. -- * When an endpoint is reset by usb_clear_halt() we must reset -- * the toggle bit in the QH. -- */ -- if (qh) { -- usb_settoggle(qh->dev, epnum, is_out, 0); -- if (!list_empty(&qh->qtd_list)) { -- WARN_ONCE(1, "clear_halt for a busy endpoint\n"); -- } else if (qh->qh_state == QH_STATE_LINKED || -- qh->qh_state == QH_STATE_COMPLETING) { -- -- /* The toggle value in the QH can't be updated -- * while the QH is active. Unlink it now; -- * re-linking will call qh_refresh(). -- */ -- if (eptype == USB_ENDPOINT_XFER_BULK) -- start_unlink_async(fotg210, qh); -- else -- start_unlink_intr(fotg210, qh); -- } -- } -- spin_unlock_irqrestore(&fotg210->lock, flags); --} -- --static int fotg210_get_frame(struct usb_hcd *hcd) --{ -- struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); -- -- return (fotg210_read_frame_index(fotg210) >> 3) % -- fotg210->periodic_size; --} -- --/* The EHCI in ChipIdea HDRC cannot be a separate module or device, -- * because its registers (and irq) are shared between host/gadget/otg -- * functions and in order to facilitate role switching we cannot -- * give the fotg210 driver exclusive access to those. -- */ --MODULE_DESCRIPTION(DRIVER_DESC); --MODULE_AUTHOR(DRIVER_AUTHOR); --MODULE_LICENSE("GPL"); -- --static const struct hc_driver fotg210_fotg210_hc_driver = { -- .description = hcd_name, -- .product_desc = "Faraday USB2.0 Host Controller", -- .hcd_priv_size = sizeof(struct fotg210_hcd), -- -- /* -- * generic hardware linkage -- */ -- .irq = fotg210_irq, -- .flags = HCD_MEMORY | HCD_DMA | HCD_USB2, -- -- /* -- * basic lifecycle operations -- */ -- .reset = hcd_fotg210_init, -- .start = fotg210_run, -- .stop = fotg210_stop, -- .shutdown = fotg210_shutdown, -- -- /* -- * managing i/o requests and associated device resources -- */ -- .urb_enqueue = fotg210_urb_enqueue, -- .urb_dequeue = fotg210_urb_dequeue, -- .endpoint_disable = fotg210_endpoint_disable, -- .endpoint_reset = fotg210_endpoint_reset, -- -- /* -- * scheduling support -- */ -- .get_frame_number = fotg210_get_frame, -- -- /* -- * root hub support -- */ -- .hub_status_data = fotg210_hub_status_data, -- .hub_control = fotg210_hub_control, -- .bus_suspend = fotg210_bus_suspend, -- .bus_resume = fotg210_bus_resume, -- -- .relinquish_port = fotg210_relinquish_port, -- .port_handed_over = fotg210_port_handed_over, -- -- .clear_tt_buffer_complete = fotg210_clear_tt_buffer_complete, --}; -- --static void fotg210_init(struct fotg210_hcd *fotg210) --{ -- u32 value; -- -- iowrite32(GMIR_MDEV_INT | GMIR_MOTG_INT | GMIR_INT_POLARITY, -- &fotg210->regs->gmir); -- -- value = ioread32(&fotg210->regs->otgcsr); -- value &= ~OTGCSR_A_BUS_DROP; -- value |= OTGCSR_A_BUS_REQ; -- iowrite32(value, &fotg210->regs->otgcsr); --} -- --/* -- * fotg210_hcd_probe - initialize faraday FOTG210 HCDs -- * -- * Allocates basic resources for this USB host controller, and -- * then invokes the start() method for the HCD associated with it -- * through the hotplug entry's driver_data. -- */ --static int fotg210_hcd_probe(struct platform_device *pdev) --{ -- struct device *dev = &pdev->dev; -- struct usb_hcd *hcd; -- struct resource *res; -- int irq; -- int retval; -- struct fotg210_hcd *fotg210; -- -- if (usb_disabled()) -- return -ENODEV; -- -- pdev->dev.power.power_state = PMSG_ON; -- -- irq = platform_get_irq(pdev, 0); -- if (irq < 0) -- return irq; -- -- hcd = usb_create_hcd(&fotg210_fotg210_hc_driver, dev, -- dev_name(dev)); -- if (!hcd) { -- dev_err(dev, "failed to create hcd\n"); -- retval = -ENOMEM; -- goto fail_create_hcd; -- } -- -- hcd->has_tt = 1; -- -- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -- hcd->regs = devm_ioremap_resource(&pdev->dev, res); -- if (IS_ERR(hcd->regs)) { -- retval = PTR_ERR(hcd->regs); -- goto failed_put_hcd; -- } -- -- hcd->rsrc_start = res->start; -- hcd->rsrc_len = resource_size(res); -- -- fotg210 = hcd_to_fotg210(hcd); -- -- fotg210->caps = hcd->regs; -- -- /* It's OK not to supply this clock */ -- fotg210->pclk = clk_get(dev, "PCLK"); -- if (!IS_ERR(fotg210->pclk)) { -- retval = clk_prepare_enable(fotg210->pclk); -- if (retval) { -- dev_err(dev, "failed to enable PCLK\n"); -- goto failed_put_hcd; -- } -- } else if (PTR_ERR(fotg210->pclk) == -EPROBE_DEFER) { -- /* -- * Percolate deferrals, for anything else, -- * just live without the clocking. -- */ -- retval = PTR_ERR(fotg210->pclk); -- goto failed_dis_clk; -- } -- -- retval = fotg210_setup(hcd); -- if (retval) -- goto failed_dis_clk; -- -- fotg210_init(fotg210); -- -- retval = usb_add_hcd(hcd, irq, IRQF_SHARED); -- if (retval) { -- dev_err(dev, "failed to add hcd with err %d\n", retval); -- goto failed_dis_clk; -- } -- device_wakeup_enable(hcd->self.controller); -- platform_set_drvdata(pdev, hcd); -- -- return retval; -- --failed_dis_clk: -- if (!IS_ERR(fotg210->pclk)) { -- clk_disable_unprepare(fotg210->pclk); -- clk_put(fotg210->pclk); -- } --failed_put_hcd: -- usb_put_hcd(hcd); --fail_create_hcd: -- dev_err(dev, "init %s fail, %d\n", dev_name(dev), retval); -- return retval; --} -- --/* -- * fotg210_hcd_remove - shutdown processing for EHCI HCDs -- * @dev: USB Host Controller being removed -- * -- */ --static int fotg210_hcd_remove(struct platform_device *pdev) --{ -- struct usb_hcd *hcd = platform_get_drvdata(pdev); -- struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); -- -- if (!IS_ERR(fotg210->pclk)) { -- clk_disable_unprepare(fotg210->pclk); -- clk_put(fotg210->pclk); -- } -- -- usb_remove_hcd(hcd); -- usb_put_hcd(hcd); -- -- return 0; --} -- --#ifdef CONFIG_OF --static const struct of_device_id fotg210_of_match[] = { -- { .compatible = "faraday,fotg210" }, -- {}, --}; --MODULE_DEVICE_TABLE(of, fotg210_of_match); --#endif -- --static struct platform_driver fotg210_hcd_driver = { -- .driver = { -- .name = "fotg210-hcd", -- .of_match_table = of_match_ptr(fotg210_of_match), -- }, -- .probe = fotg210_hcd_probe, -- .remove = fotg210_hcd_remove, --}; -- --static int __init fotg210_hcd_init(void) --{ -- int retval = 0; -- -- if (usb_disabled()) -- return -ENODEV; -- -- set_bit(USB_EHCI_LOADED, &usb_hcds_loaded); -- if (test_bit(USB_UHCI_LOADED, &usb_hcds_loaded) || -- test_bit(USB_OHCI_LOADED, &usb_hcds_loaded)) -- pr_warn("Warning! fotg210_hcd should always be loaded before uhci_hcd and ohci_hcd, not after\n"); -- -- pr_debug("%s: block sizes: qh %zd qtd %zd itd %zd\n", -- hcd_name, sizeof(struct fotg210_qh), -- sizeof(struct fotg210_qtd), -- sizeof(struct fotg210_itd)); -- -- fotg210_debug_root = debugfs_create_dir("fotg210", usb_debug_root); -- -- retval = platform_driver_register(&fotg210_hcd_driver); -- if (retval < 0) -- goto clean; -- return retval; -- --clean: -- debugfs_remove(fotg210_debug_root); -- fotg210_debug_root = NULL; -- -- clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded); -- return retval; --} --module_init(fotg210_hcd_init); -- --static void __exit fotg210_hcd_cleanup(void) --{ -- platform_driver_unregister(&fotg210_hcd_driver); -- debugfs_remove(fotg210_debug_root); -- clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded); --} --module_exit(fotg210_hcd_cleanup); ---- /dev/null -+++ b/drivers/usb/fotg210/fotg210-hcd.c -@@ -0,0 +1,5727 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* Faraday FOTG210 EHCI-like driver -+ * -+ * Copyright (c) 2013 Faraday Technology Corporation -+ * -+ * Author: Yuan-Hsin Chen -+ * Feng-Hsin Chiang -+ * Po-Yu Chuang -+ * -+ * Most of code borrowed from the Linux-3.7 EHCI driver -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#define DRIVER_AUTHOR "Yuan-Hsin Chen" -+#define DRIVER_DESC "FOTG210 Host Controller (EHCI) Driver" -+static const char hcd_name[] = "fotg210_hcd"; -+ -+#undef FOTG210_URB_TRACE -+#define FOTG210_STATS -+ -+/* magic numbers that can affect system performance */ -+#define FOTG210_TUNE_CERR 3 /* 0-3 qtd retries; 0 == don't stop */ -+#define FOTG210_TUNE_RL_HS 4 /* nak throttle; see 4.9 */ -+#define FOTG210_TUNE_RL_TT 0 -+#define FOTG210_TUNE_MULT_HS 1 /* 1-3 transactions/uframe; 4.10.3 */ -+#define FOTG210_TUNE_MULT_TT 1 -+ -+/* Some drivers think it's safe to schedule isochronous transfers more than 256 -+ * ms into the future (partly as a result of an old bug in the scheduling -+ * code). In an attempt to avoid trouble, we will use a minimum scheduling -+ * length of 512 frames instead of 256. -+ */ -+#define FOTG210_TUNE_FLS 1 /* (medium) 512-frame schedule */ -+ -+/* Initial IRQ latency: faster than hw default */ -+static int log2_irq_thresh; /* 0 to 6 */ -+module_param(log2_irq_thresh, int, S_IRUGO); -+MODULE_PARM_DESC(log2_irq_thresh, "log2 IRQ latency, 1-64 microframes"); -+ -+/* initial park setting: slower than hw default */ -+static unsigned park; -+module_param(park, uint, S_IRUGO); -+MODULE_PARM_DESC(park, "park setting; 1-3 back-to-back async packets"); -+ -+/* for link power management(LPM) feature */ -+static unsigned int hird; -+module_param(hird, int, S_IRUGO); -+MODULE_PARM_DESC(hird, "host initiated resume duration, +1 for each 75us"); -+ -+#define INTR_MASK (STS_IAA | STS_FATAL | STS_PCD | STS_ERR | STS_INT) -+ -+#include "fotg210-hcd.h" -+ -+#define fotg210_dbg(fotg210, fmt, args...) \ -+ dev_dbg(fotg210_to_hcd(fotg210)->self.controller, fmt, ## args) -+#define fotg210_err(fotg210, fmt, args...) \ -+ dev_err(fotg210_to_hcd(fotg210)->self.controller, fmt, ## args) -+#define fotg210_info(fotg210, fmt, args...) \ -+ dev_info(fotg210_to_hcd(fotg210)->self.controller, fmt, ## args) -+#define fotg210_warn(fotg210, fmt, args...) \ -+ dev_warn(fotg210_to_hcd(fotg210)->self.controller, fmt, ## args) -+ -+/* check the values in the HCSPARAMS register (host controller _Structural_ -+ * parameters) see EHCI spec, Table 2-4 for each value -+ */ -+static void dbg_hcs_params(struct fotg210_hcd *fotg210, char *label) -+{ -+ u32 params = fotg210_readl(fotg210, &fotg210->caps->hcs_params); -+ -+ fotg210_dbg(fotg210, "%s hcs_params 0x%x ports=%d\n", label, params, -+ HCS_N_PORTS(params)); -+} -+ -+/* check the values in the HCCPARAMS register (host controller _Capability_ -+ * parameters) see EHCI Spec, Table 2-5 for each value -+ */ -+static void dbg_hcc_params(struct fotg210_hcd *fotg210, char *label) -+{ -+ u32 params = fotg210_readl(fotg210, &fotg210->caps->hcc_params); -+ -+ fotg210_dbg(fotg210, "%s hcc_params %04x uframes %s%s\n", label, -+ params, -+ HCC_PGM_FRAMELISTLEN(params) ? "256/512/1024" : "1024", -+ HCC_CANPARK(params) ? " park" : ""); -+} -+ -+static void __maybe_unused -+dbg_qtd(const char *label, struct fotg210_hcd *fotg210, struct fotg210_qtd *qtd) -+{ -+ fotg210_dbg(fotg210, "%s td %p n%08x %08x t%08x p0=%08x\n", label, qtd, -+ hc32_to_cpup(fotg210, &qtd->hw_next), -+ hc32_to_cpup(fotg210, &qtd->hw_alt_next), -+ hc32_to_cpup(fotg210, &qtd->hw_token), -+ hc32_to_cpup(fotg210, &qtd->hw_buf[0])); -+ if (qtd->hw_buf[1]) -+ fotg210_dbg(fotg210, " p1=%08x p2=%08x p3=%08x p4=%08x\n", -+ hc32_to_cpup(fotg210, &qtd->hw_buf[1]), -+ hc32_to_cpup(fotg210, &qtd->hw_buf[2]), -+ hc32_to_cpup(fotg210, &qtd->hw_buf[3]), -+ hc32_to_cpup(fotg210, &qtd->hw_buf[4])); -+} -+ -+static void __maybe_unused -+dbg_qh(const char *label, struct fotg210_hcd *fotg210, struct fotg210_qh *qh) -+{ -+ struct fotg210_qh_hw *hw = qh->hw; -+ -+ fotg210_dbg(fotg210, "%s qh %p n%08x info %x %x qtd %x\n", label, qh, -+ hw->hw_next, hw->hw_info1, hw->hw_info2, -+ hw->hw_current); -+ -+ dbg_qtd("overlay", fotg210, (struct fotg210_qtd *) &hw->hw_qtd_next); -+} -+ -+static void __maybe_unused -+dbg_itd(const char *label, struct fotg210_hcd *fotg210, struct fotg210_itd *itd) -+{ -+ fotg210_dbg(fotg210, "%s[%d] itd %p, next %08x, urb %p\n", label, -+ itd->frame, itd, hc32_to_cpu(fotg210, itd->hw_next), -+ itd->urb); -+ -+ fotg210_dbg(fotg210, -+ " trans: %08x %08x %08x %08x %08x %08x %08x %08x\n", -+ hc32_to_cpu(fotg210, itd->hw_transaction[0]), -+ hc32_to_cpu(fotg210, itd->hw_transaction[1]), -+ hc32_to_cpu(fotg210, itd->hw_transaction[2]), -+ hc32_to_cpu(fotg210, itd->hw_transaction[3]), -+ hc32_to_cpu(fotg210, itd->hw_transaction[4]), -+ hc32_to_cpu(fotg210, itd->hw_transaction[5]), -+ hc32_to_cpu(fotg210, itd->hw_transaction[6]), -+ hc32_to_cpu(fotg210, itd->hw_transaction[7])); -+ -+ fotg210_dbg(fotg210, -+ " buf: %08x %08x %08x %08x %08x %08x %08x\n", -+ hc32_to_cpu(fotg210, itd->hw_bufp[0]), -+ hc32_to_cpu(fotg210, itd->hw_bufp[1]), -+ hc32_to_cpu(fotg210, itd->hw_bufp[2]), -+ hc32_to_cpu(fotg210, itd->hw_bufp[3]), -+ hc32_to_cpu(fotg210, itd->hw_bufp[4]), -+ hc32_to_cpu(fotg210, itd->hw_bufp[5]), -+ hc32_to_cpu(fotg210, itd->hw_bufp[6])); -+ -+ fotg210_dbg(fotg210, " index: %d %d %d %d %d %d %d %d\n", -+ itd->index[0], itd->index[1], itd->index[2], -+ itd->index[3], itd->index[4], itd->index[5], -+ itd->index[6], itd->index[7]); -+} -+ -+static int __maybe_unused -+dbg_status_buf(char *buf, unsigned len, const char *label, u32 status) -+{ -+ return scnprintf(buf, len, "%s%sstatus %04x%s%s%s%s%s%s%s%s%s%s", -+ label, label[0] ? " " : "", status, -+ (status & STS_ASS) ? " Async" : "", -+ (status & STS_PSS) ? " Periodic" : "", -+ (status & STS_RECL) ? " Recl" : "", -+ (status & STS_HALT) ? " Halt" : "", -+ (status & STS_IAA) ? " IAA" : "", -+ (status & STS_FATAL) ? " FATAL" : "", -+ (status & STS_FLR) ? " FLR" : "", -+ (status & STS_PCD) ? " PCD" : "", -+ (status & STS_ERR) ? " ERR" : "", -+ (status & STS_INT) ? " INT" : ""); -+} -+ -+static int __maybe_unused -+dbg_intr_buf(char *buf, unsigned len, const char *label, u32 enable) -+{ -+ return scnprintf(buf, len, "%s%sintrenable %02x%s%s%s%s%s%s", -+ label, label[0] ? " " : "", enable, -+ (enable & STS_IAA) ? " IAA" : "", -+ (enable & STS_FATAL) ? " FATAL" : "", -+ (enable & STS_FLR) ? " FLR" : "", -+ (enable & STS_PCD) ? " PCD" : "", -+ (enable & STS_ERR) ? " ERR" : "", -+ (enable & STS_INT) ? " INT" : ""); -+} -+ -+static const char *const fls_strings[] = { "1024", "512", "256", "??" }; -+ -+static int dbg_command_buf(char *buf, unsigned len, const char *label, -+ u32 command) -+{ -+ return scnprintf(buf, len, -+ "%s%scommand %07x %s=%d ithresh=%d%s%s%s period=%s%s %s", -+ label, label[0] ? " " : "", command, -+ (command & CMD_PARK) ? " park" : "(park)", -+ CMD_PARK_CNT(command), -+ (command >> 16) & 0x3f, -+ (command & CMD_IAAD) ? " IAAD" : "", -+ (command & CMD_ASE) ? " Async" : "", -+ (command & CMD_PSE) ? " Periodic" : "", -+ fls_strings[(command >> 2) & 0x3], -+ (command & CMD_RESET) ? " Reset" : "", -+ (command & CMD_RUN) ? "RUN" : "HALT"); -+} -+ -+static char *dbg_port_buf(char *buf, unsigned len, const char *label, int port, -+ u32 status) -+{ -+ char *sig; -+ -+ /* signaling state */ -+ switch (status & (3 << 10)) { -+ case 0 << 10: -+ sig = "se0"; -+ break; -+ case 1 << 10: -+ sig = "k"; -+ break; /* low speed */ -+ case 2 << 10: -+ sig = "j"; -+ break; -+ default: -+ sig = "?"; -+ break; -+ } -+ -+ scnprintf(buf, len, "%s%sport:%d status %06x %d sig=%s%s%s%s%s%s%s%s", -+ label, label[0] ? " " : "", port, status, -+ status >> 25, /*device address */ -+ sig, -+ (status & PORT_RESET) ? " RESET" : "", -+ (status & PORT_SUSPEND) ? " SUSPEND" : "", -+ (status & PORT_RESUME) ? " RESUME" : "", -+ (status & PORT_PEC) ? " PEC" : "", -+ (status & PORT_PE) ? " PE" : "", -+ (status & PORT_CSC) ? " CSC" : "", -+ (status & PORT_CONNECT) ? " CONNECT" : ""); -+ -+ return buf; -+} -+ -+/* functions have the "wrong" filename when they're output... */ -+#define dbg_status(fotg210, label, status) { \ -+ char _buf[80]; \ -+ dbg_status_buf(_buf, sizeof(_buf), label, status); \ -+ fotg210_dbg(fotg210, "%s\n", _buf); \ -+} -+ -+#define dbg_cmd(fotg210, label, command) { \ -+ char _buf[80]; \ -+ dbg_command_buf(_buf, sizeof(_buf), label, command); \ -+ fotg210_dbg(fotg210, "%s\n", _buf); \ -+} -+ -+#define dbg_port(fotg210, label, port, status) { \ -+ char _buf[80]; \ -+ fotg210_dbg(fotg210, "%s\n", \ -+ dbg_port_buf(_buf, sizeof(_buf), label, port, status));\ -+} -+ -+/* troubleshooting help: expose state in debugfs */ -+static int debug_async_open(struct inode *, struct file *); -+static int debug_periodic_open(struct inode *, struct file *); -+static int debug_registers_open(struct inode *, struct file *); -+static int debug_async_open(struct inode *, struct file *); -+ -+static ssize_t debug_output(struct file*, char __user*, size_t, loff_t*); -+static int debug_close(struct inode *, struct file *); -+ -+static const struct file_operations debug_async_fops = { -+ .owner = THIS_MODULE, -+ .open = debug_async_open, -+ .read = debug_output, -+ .release = debug_close, -+ .llseek = default_llseek, -+}; -+static const struct file_operations debug_periodic_fops = { -+ .owner = THIS_MODULE, -+ .open = debug_periodic_open, -+ .read = debug_output, -+ .release = debug_close, -+ .llseek = default_llseek, -+}; -+static const struct file_operations debug_registers_fops = { -+ .owner = THIS_MODULE, -+ .open = debug_registers_open, -+ .read = debug_output, -+ .release = debug_close, -+ .llseek = default_llseek, -+}; -+ -+static struct dentry *fotg210_debug_root; -+ -+struct debug_buffer { -+ ssize_t (*fill_func)(struct debug_buffer *); /* fill method */ -+ struct usb_bus *bus; -+ struct mutex mutex; /* protect filling of buffer */ -+ size_t count; /* number of characters filled into buffer */ -+ char *output_buf; -+ size_t alloc_size; -+}; -+ -+static inline char speed_char(u32 scratch) -+{ -+ switch (scratch & (3 << 12)) { -+ case QH_FULL_SPEED: -+ return 'f'; -+ -+ case QH_LOW_SPEED: -+ return 'l'; -+ -+ case QH_HIGH_SPEED: -+ return 'h'; -+ -+ default: -+ return '?'; -+ } -+} -+ -+static inline char token_mark(struct fotg210_hcd *fotg210, __hc32 token) -+{ -+ __u32 v = hc32_to_cpu(fotg210, token); -+ -+ if (v & QTD_STS_ACTIVE) -+ return '*'; -+ if (v & QTD_STS_HALT) -+ return '-'; -+ if (!IS_SHORT_READ(v)) -+ return ' '; -+ /* tries to advance through hw_alt_next */ -+ return '/'; -+} -+ -+static void qh_lines(struct fotg210_hcd *fotg210, struct fotg210_qh *qh, -+ char **nextp, unsigned *sizep) -+{ -+ u32 scratch; -+ u32 hw_curr; -+ struct fotg210_qtd *td; -+ unsigned temp; -+ unsigned size = *sizep; -+ char *next = *nextp; -+ char mark; -+ __le32 list_end = FOTG210_LIST_END(fotg210); -+ struct fotg210_qh_hw *hw = qh->hw; -+ -+ if (hw->hw_qtd_next == list_end) /* NEC does this */ -+ mark = '@'; -+ else -+ mark = token_mark(fotg210, hw->hw_token); -+ if (mark == '/') { /* qh_alt_next controls qh advance? */ -+ if ((hw->hw_alt_next & QTD_MASK(fotg210)) == -+ fotg210->async->hw->hw_alt_next) -+ mark = '#'; /* blocked */ -+ else if (hw->hw_alt_next == list_end) -+ mark = '.'; /* use hw_qtd_next */ -+ /* else alt_next points to some other qtd */ -+ } -+ scratch = hc32_to_cpup(fotg210, &hw->hw_info1); -+ hw_curr = (mark == '*') ? hc32_to_cpup(fotg210, &hw->hw_current) : 0; -+ temp = scnprintf(next, size, -+ "qh/%p dev%d %cs ep%d %08x %08x(%08x%c %s nak%d)", -+ qh, scratch & 0x007f, -+ speed_char(scratch), -+ (scratch >> 8) & 0x000f, -+ scratch, hc32_to_cpup(fotg210, &hw->hw_info2), -+ hc32_to_cpup(fotg210, &hw->hw_token), mark, -+ (cpu_to_hc32(fotg210, QTD_TOGGLE) & hw->hw_token) -+ ? "data1" : "data0", -+ (hc32_to_cpup(fotg210, &hw->hw_alt_next) >> 1) & 0x0f); -+ size -= temp; -+ next += temp; -+ -+ /* hc may be modifying the list as we read it ... */ -+ list_for_each_entry(td, &qh->qtd_list, qtd_list) { -+ scratch = hc32_to_cpup(fotg210, &td->hw_token); -+ mark = ' '; -+ if (hw_curr == td->qtd_dma) -+ mark = '*'; -+ else if (hw->hw_qtd_next == cpu_to_hc32(fotg210, td->qtd_dma)) -+ mark = '+'; -+ else if (QTD_LENGTH(scratch)) { -+ if (td->hw_alt_next == fotg210->async->hw->hw_alt_next) -+ mark = '#'; -+ else if (td->hw_alt_next != list_end) -+ mark = '/'; -+ } -+ temp = snprintf(next, size, -+ "\n\t%p%c%s len=%d %08x urb %p", -+ td, mark, ({ char *tmp; -+ switch ((scratch>>8)&0x03) { -+ case 0: -+ tmp = "out"; -+ break; -+ case 1: -+ tmp = "in"; -+ break; -+ case 2: -+ tmp = "setup"; -+ break; -+ default: -+ tmp = "?"; -+ break; -+ } tmp; }), -+ (scratch >> 16) & 0x7fff, -+ scratch, -+ td->urb); -+ if (size < temp) -+ temp = size; -+ size -= temp; -+ next += temp; -+ if (temp == size) -+ goto done; -+ } -+ -+ temp = snprintf(next, size, "\n"); -+ if (size < temp) -+ temp = size; -+ -+ size -= temp; -+ next += temp; -+ -+done: -+ *sizep = size; -+ *nextp = next; -+} -+ -+static ssize_t fill_async_buffer(struct debug_buffer *buf) -+{ -+ struct usb_hcd *hcd; -+ struct fotg210_hcd *fotg210; -+ unsigned long flags; -+ unsigned temp, size; -+ char *next; -+ struct fotg210_qh *qh; -+ -+ hcd = bus_to_hcd(buf->bus); -+ fotg210 = hcd_to_fotg210(hcd); -+ next = buf->output_buf; -+ size = buf->alloc_size; -+ -+ *next = 0; -+ -+ /* dumps a snapshot of the async schedule. -+ * usually empty except for long-term bulk reads, or head. -+ * one QH per line, and TDs we know about -+ */ -+ spin_lock_irqsave(&fotg210->lock, flags); -+ for (qh = fotg210->async->qh_next.qh; size > 0 && qh; -+ qh = qh->qh_next.qh) -+ qh_lines(fotg210, qh, &next, &size); -+ if (fotg210->async_unlink && size > 0) { -+ temp = scnprintf(next, size, "\nunlink =\n"); -+ size -= temp; -+ next += temp; -+ -+ for (qh = fotg210->async_unlink; size > 0 && qh; -+ qh = qh->unlink_next) -+ qh_lines(fotg210, qh, &next, &size); -+ } -+ spin_unlock_irqrestore(&fotg210->lock, flags); -+ -+ return strlen(buf->output_buf); -+} -+ -+/* count tds, get ep direction */ -+static unsigned output_buf_tds_dir(char *buf, struct fotg210_hcd *fotg210, -+ struct fotg210_qh_hw *hw, struct fotg210_qh *qh, unsigned size) -+{ -+ u32 scratch = hc32_to_cpup(fotg210, &hw->hw_info1); -+ struct fotg210_qtd *qtd; -+ char *type = ""; -+ unsigned temp = 0; -+ -+ /* count tds, get ep direction */ -+ list_for_each_entry(qtd, &qh->qtd_list, qtd_list) { -+ temp++; -+ switch ((hc32_to_cpu(fotg210, qtd->hw_token) >> 8) & 0x03) { -+ case 0: -+ type = "out"; -+ continue; -+ case 1: -+ type = "in"; -+ continue; -+ } -+ } -+ -+ return scnprintf(buf, size, "(%c%d ep%d%s [%d/%d] q%d p%d)", -+ speed_char(scratch), scratch & 0x007f, -+ (scratch >> 8) & 0x000f, type, qh->usecs, -+ qh->c_usecs, temp, (scratch >> 16) & 0x7ff); -+} -+ -+#define DBG_SCHED_LIMIT 64 -+static ssize_t fill_periodic_buffer(struct debug_buffer *buf) -+{ -+ struct usb_hcd *hcd; -+ struct fotg210_hcd *fotg210; -+ unsigned long flags; -+ union fotg210_shadow p, *seen; -+ unsigned temp, size, seen_count; -+ char *next; -+ unsigned i; -+ __hc32 tag; -+ -+ seen = kmalloc_array(DBG_SCHED_LIMIT, sizeof(*seen), GFP_ATOMIC); -+ if (!seen) -+ return 0; -+ -+ seen_count = 0; -+ -+ hcd = bus_to_hcd(buf->bus); -+ fotg210 = hcd_to_fotg210(hcd); -+ next = buf->output_buf; -+ size = buf->alloc_size; -+ -+ temp = scnprintf(next, size, "size = %d\n", fotg210->periodic_size); -+ size -= temp; -+ next += temp; -+ -+ /* dump a snapshot of the periodic schedule. -+ * iso changes, interrupt usually doesn't. -+ */ -+ spin_lock_irqsave(&fotg210->lock, flags); -+ for (i = 0; i < fotg210->periodic_size; i++) { -+ p = fotg210->pshadow[i]; -+ if (likely(!p.ptr)) -+ continue; -+ -+ tag = Q_NEXT_TYPE(fotg210, fotg210->periodic[i]); -+ -+ temp = scnprintf(next, size, "%4d: ", i); -+ size -= temp; -+ next += temp; -+ -+ do { -+ struct fotg210_qh_hw *hw; -+ -+ switch (hc32_to_cpu(fotg210, tag)) { -+ case Q_TYPE_QH: -+ hw = p.qh->hw; -+ temp = scnprintf(next, size, " qh%d-%04x/%p", -+ p.qh->period, -+ hc32_to_cpup(fotg210, -+ &hw->hw_info2) -+ /* uframe masks */ -+ & (QH_CMASK | QH_SMASK), -+ p.qh); -+ size -= temp; -+ next += temp; -+ /* don't repeat what follows this qh */ -+ for (temp = 0; temp < seen_count; temp++) { -+ if (seen[temp].ptr != p.ptr) -+ continue; -+ if (p.qh->qh_next.ptr) { -+ temp = scnprintf(next, size, -+ " ..."); -+ size -= temp; -+ next += temp; -+ } -+ break; -+ } -+ /* show more info the first time around */ -+ if (temp == seen_count) { -+ temp = output_buf_tds_dir(next, -+ fotg210, hw, -+ p.qh, size); -+ -+ if (seen_count < DBG_SCHED_LIMIT) -+ seen[seen_count++].qh = p.qh; -+ } else -+ temp = 0; -+ tag = Q_NEXT_TYPE(fotg210, hw->hw_next); -+ p = p.qh->qh_next; -+ break; -+ case Q_TYPE_FSTN: -+ temp = scnprintf(next, size, -+ " fstn-%8x/%p", -+ p.fstn->hw_prev, p.fstn); -+ tag = Q_NEXT_TYPE(fotg210, p.fstn->hw_next); -+ p = p.fstn->fstn_next; -+ break; -+ case Q_TYPE_ITD: -+ temp = scnprintf(next, size, -+ " itd/%p", p.itd); -+ tag = Q_NEXT_TYPE(fotg210, p.itd->hw_next); -+ p = p.itd->itd_next; -+ break; -+ } -+ size -= temp; -+ next += temp; -+ } while (p.ptr); -+ -+ temp = scnprintf(next, size, "\n"); -+ size -= temp; -+ next += temp; -+ } -+ spin_unlock_irqrestore(&fotg210->lock, flags); -+ kfree(seen); -+ -+ return buf->alloc_size - size; -+} -+#undef DBG_SCHED_LIMIT -+ -+static const char *rh_state_string(struct fotg210_hcd *fotg210) -+{ -+ switch (fotg210->rh_state) { -+ case FOTG210_RH_HALTED: -+ return "halted"; -+ case FOTG210_RH_SUSPENDED: -+ return "suspended"; -+ case FOTG210_RH_RUNNING: -+ return "running"; -+ case FOTG210_RH_STOPPING: -+ return "stopping"; -+ } -+ return "?"; -+} -+ -+static ssize_t fill_registers_buffer(struct debug_buffer *buf) -+{ -+ struct usb_hcd *hcd; -+ struct fotg210_hcd *fotg210; -+ unsigned long flags; -+ unsigned temp, size, i; -+ char *next, scratch[80]; -+ static const char fmt[] = "%*s\n"; -+ static const char label[] = ""; -+ -+ hcd = bus_to_hcd(buf->bus); -+ fotg210 = hcd_to_fotg210(hcd); -+ next = buf->output_buf; -+ size = buf->alloc_size; -+ -+ spin_lock_irqsave(&fotg210->lock, flags); -+ -+ if (!HCD_HW_ACCESSIBLE(hcd)) { -+ size = scnprintf(next, size, -+ "bus %s, device %s\n" -+ "%s\n" -+ "SUSPENDED(no register access)\n", -+ hcd->self.controller->bus->name, -+ dev_name(hcd->self.controller), -+ hcd->product_desc); -+ goto done; -+ } -+ -+ /* Capability Registers */ -+ i = HC_VERSION(fotg210, fotg210_readl(fotg210, -+ &fotg210->caps->hc_capbase)); -+ temp = scnprintf(next, size, -+ "bus %s, device %s\n" -+ "%s\n" -+ "EHCI %x.%02x, rh state %s\n", -+ hcd->self.controller->bus->name, -+ dev_name(hcd->self.controller), -+ hcd->product_desc, -+ i >> 8, i & 0x0ff, rh_state_string(fotg210)); -+ size -= temp; -+ next += temp; -+ -+ /* FIXME interpret both types of params */ -+ i = fotg210_readl(fotg210, &fotg210->caps->hcs_params); -+ temp = scnprintf(next, size, "structural params 0x%08x\n", i); -+ size -= temp; -+ next += temp; -+ -+ i = fotg210_readl(fotg210, &fotg210->caps->hcc_params); -+ temp = scnprintf(next, size, "capability params 0x%08x\n", i); -+ size -= temp; -+ next += temp; -+ -+ /* Operational Registers */ -+ temp = dbg_status_buf(scratch, sizeof(scratch), label, -+ fotg210_readl(fotg210, &fotg210->regs->status)); -+ temp = scnprintf(next, size, fmt, temp, scratch); -+ size -= temp; -+ next += temp; -+ -+ temp = dbg_command_buf(scratch, sizeof(scratch), label, -+ fotg210_readl(fotg210, &fotg210->regs->command)); -+ temp = scnprintf(next, size, fmt, temp, scratch); -+ size -= temp; -+ next += temp; -+ -+ temp = dbg_intr_buf(scratch, sizeof(scratch), label, -+ fotg210_readl(fotg210, &fotg210->regs->intr_enable)); -+ temp = scnprintf(next, size, fmt, temp, scratch); -+ size -= temp; -+ next += temp; -+ -+ temp = scnprintf(next, size, "uframe %04x\n", -+ fotg210_read_frame_index(fotg210)); -+ size -= temp; -+ next += temp; -+ -+ if (fotg210->async_unlink) { -+ temp = scnprintf(next, size, "async unlink qh %p\n", -+ fotg210->async_unlink); -+ size -= temp; -+ next += temp; -+ } -+ -+#ifdef FOTG210_STATS -+ temp = scnprintf(next, size, -+ "irq normal %ld err %ld iaa %ld(lost %ld)\n", -+ fotg210->stats.normal, fotg210->stats.error, -+ fotg210->stats.iaa, fotg210->stats.lost_iaa); -+ size -= temp; -+ next += temp; -+ -+ temp = scnprintf(next, size, "complete %ld unlink %ld\n", -+ fotg210->stats.complete, fotg210->stats.unlink); -+ size -= temp; -+ next += temp; -+#endif -+ -+done: -+ spin_unlock_irqrestore(&fotg210->lock, flags); -+ -+ return buf->alloc_size - size; -+} -+ -+static struct debug_buffer -+*alloc_buffer(struct usb_bus *bus, ssize_t (*fill_func)(struct debug_buffer *)) -+{ -+ struct debug_buffer *buf; -+ -+ buf = kzalloc(sizeof(struct debug_buffer), GFP_KERNEL); -+ -+ if (buf) { -+ buf->bus = bus; -+ buf->fill_func = fill_func; -+ mutex_init(&buf->mutex); -+ buf->alloc_size = PAGE_SIZE; -+ } -+ -+ return buf; -+} -+ -+static int fill_buffer(struct debug_buffer *buf) -+{ -+ int ret = 0; -+ -+ if (!buf->output_buf) -+ buf->output_buf = vmalloc(buf->alloc_size); -+ -+ if (!buf->output_buf) { -+ ret = -ENOMEM; -+ goto out; -+ } -+ -+ ret = buf->fill_func(buf); -+ -+ if (ret >= 0) { -+ buf->count = ret; -+ ret = 0; -+ } -+ -+out: -+ return ret; -+} -+ -+static ssize_t debug_output(struct file *file, char __user *user_buf, -+ size_t len, loff_t *offset) -+{ -+ struct debug_buffer *buf = file->private_data; -+ int ret = 0; -+ -+ mutex_lock(&buf->mutex); -+ if (buf->count == 0) { -+ ret = fill_buffer(buf); -+ if (ret != 0) { -+ mutex_unlock(&buf->mutex); -+ goto out; -+ } -+ } -+ mutex_unlock(&buf->mutex); -+ -+ ret = simple_read_from_buffer(user_buf, len, offset, -+ buf->output_buf, buf->count); -+ -+out: -+ return ret; -+ -+} -+ -+static int debug_close(struct inode *inode, struct file *file) -+{ -+ struct debug_buffer *buf = file->private_data; -+ -+ if (buf) { -+ vfree(buf->output_buf); -+ kfree(buf); -+ } -+ -+ return 0; -+} -+static int debug_async_open(struct inode *inode, struct file *file) -+{ -+ file->private_data = alloc_buffer(inode->i_private, fill_async_buffer); -+ -+ return file->private_data ? 0 : -ENOMEM; -+} -+ -+static int debug_periodic_open(struct inode *inode, struct file *file) -+{ -+ struct debug_buffer *buf; -+ -+ buf = alloc_buffer(inode->i_private, fill_periodic_buffer); -+ if (!buf) -+ return -ENOMEM; -+ -+ buf->alloc_size = (sizeof(void *) == 4 ? 6 : 8)*PAGE_SIZE; -+ file->private_data = buf; -+ return 0; -+} -+ -+static int debug_registers_open(struct inode *inode, struct file *file) -+{ -+ file->private_data = alloc_buffer(inode->i_private, -+ fill_registers_buffer); -+ -+ return file->private_data ? 0 : -ENOMEM; -+} -+ -+static inline void create_debug_files(struct fotg210_hcd *fotg210) -+{ -+ struct usb_bus *bus = &fotg210_to_hcd(fotg210)->self; -+ struct dentry *root; -+ -+ root = debugfs_create_dir(bus->bus_name, fotg210_debug_root); -+ -+ debugfs_create_file("async", S_IRUGO, root, bus, &debug_async_fops); -+ debugfs_create_file("periodic", S_IRUGO, root, bus, -+ &debug_periodic_fops); -+ debugfs_create_file("registers", S_IRUGO, root, bus, -+ &debug_registers_fops); -+} -+ -+static inline void remove_debug_files(struct fotg210_hcd *fotg210) -+{ -+ struct usb_bus *bus = &fotg210_to_hcd(fotg210)->self; -+ -+ debugfs_lookup_and_remove(bus->bus_name, fotg210_debug_root); -+} -+ -+/* handshake - spin reading hc until handshake completes or fails -+ * @ptr: address of hc register to be read -+ * @mask: bits to look at in result of read -+ * @done: value of those bits when handshake succeeds -+ * @usec: timeout in microseconds -+ * -+ * Returns negative errno, or zero on success -+ * -+ * Success happens when the "mask" bits have the specified value (hardware -+ * handshake done). There are two failure modes: "usec" have passed (major -+ * hardware flakeout), or the register reads as all-ones (hardware removed). -+ * -+ * That last failure should_only happen in cases like physical cardbus eject -+ * before driver shutdown. But it also seems to be caused by bugs in cardbus -+ * bridge shutdown: shutting down the bridge before the devices using it. -+ */ -+static int handshake(struct fotg210_hcd *fotg210, void __iomem *ptr, -+ u32 mask, u32 done, int usec) -+{ -+ u32 result; -+ int ret; -+ -+ ret = readl_poll_timeout_atomic(ptr, result, -+ ((result & mask) == done || -+ result == U32_MAX), 1, usec); -+ if (result == U32_MAX) /* card removed */ -+ return -ENODEV; -+ -+ return ret; -+} -+ -+/* Force HC to halt state from unknown (EHCI spec section 2.3). -+ * Must be called with interrupts enabled and the lock not held. -+ */ -+static int fotg210_halt(struct fotg210_hcd *fotg210) -+{ -+ u32 temp; -+ -+ spin_lock_irq(&fotg210->lock); -+ -+ /* disable any irqs left enabled by previous code */ -+ fotg210_writel(fotg210, 0, &fotg210->regs->intr_enable); -+ -+ /* -+ * This routine gets called during probe before fotg210->command -+ * has been initialized, so we can't rely on its value. -+ */ -+ fotg210->command &= ~CMD_RUN; -+ temp = fotg210_readl(fotg210, &fotg210->regs->command); -+ temp &= ~(CMD_RUN | CMD_IAAD); -+ fotg210_writel(fotg210, temp, &fotg210->regs->command); -+ -+ spin_unlock_irq(&fotg210->lock); -+ synchronize_irq(fotg210_to_hcd(fotg210)->irq); -+ -+ return handshake(fotg210, &fotg210->regs->status, -+ STS_HALT, STS_HALT, 16 * 125); -+} -+ -+/* Reset a non-running (STS_HALT == 1) controller. -+ * Must be called with interrupts enabled and the lock not held. -+ */ -+static int fotg210_reset(struct fotg210_hcd *fotg210) -+{ -+ int retval; -+ u32 command = fotg210_readl(fotg210, &fotg210->regs->command); -+ -+ /* If the EHCI debug controller is active, special care must be -+ * taken before and after a host controller reset -+ */ -+ if (fotg210->debug && !dbgp_reset_prep(fotg210_to_hcd(fotg210))) -+ fotg210->debug = NULL; -+ -+ command |= CMD_RESET; -+ dbg_cmd(fotg210, "reset", command); -+ fotg210_writel(fotg210, command, &fotg210->regs->command); -+ fotg210->rh_state = FOTG210_RH_HALTED; -+ fotg210->next_statechange = jiffies; -+ retval = handshake(fotg210, &fotg210->regs->command, -+ CMD_RESET, 0, 250 * 1000); -+ -+ if (retval) -+ return retval; -+ -+ if (fotg210->debug) -+ dbgp_external_startup(fotg210_to_hcd(fotg210)); -+ -+ fotg210->port_c_suspend = fotg210->suspended_ports = -+ fotg210->resuming_ports = 0; -+ return retval; -+} -+ -+/* Idle the controller (turn off the schedules). -+ * Must be called with interrupts enabled and the lock not held. -+ */ -+static void fotg210_quiesce(struct fotg210_hcd *fotg210) -+{ -+ u32 temp; -+ -+ if (fotg210->rh_state != FOTG210_RH_RUNNING) -+ return; -+ -+ /* wait for any schedule enables/disables to take effect */ -+ temp = (fotg210->command << 10) & (STS_ASS | STS_PSS); -+ handshake(fotg210, &fotg210->regs->status, STS_ASS | STS_PSS, temp, -+ 16 * 125); -+ -+ /* then disable anything that's still active */ -+ spin_lock_irq(&fotg210->lock); -+ fotg210->command &= ~(CMD_ASE | CMD_PSE); -+ fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command); -+ spin_unlock_irq(&fotg210->lock); -+ -+ /* hardware can take 16 microframes to turn off ... */ -+ handshake(fotg210, &fotg210->regs->status, STS_ASS | STS_PSS, 0, -+ 16 * 125); -+} -+ -+static void end_unlink_async(struct fotg210_hcd *fotg210); -+static void unlink_empty_async(struct fotg210_hcd *fotg210); -+static void fotg210_work(struct fotg210_hcd *fotg210); -+static void start_unlink_intr(struct fotg210_hcd *fotg210, -+ struct fotg210_qh *qh); -+static void end_unlink_intr(struct fotg210_hcd *fotg210, struct fotg210_qh *qh); -+ -+/* Set a bit in the USBCMD register */ -+static void fotg210_set_command_bit(struct fotg210_hcd *fotg210, u32 bit) -+{ -+ fotg210->command |= bit; -+ fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command); -+ -+ /* unblock posted write */ -+ fotg210_readl(fotg210, &fotg210->regs->command); -+} -+ -+/* Clear a bit in the USBCMD register */ -+static void fotg210_clear_command_bit(struct fotg210_hcd *fotg210, u32 bit) -+{ -+ fotg210->command &= ~bit; -+ fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command); -+ -+ /* unblock posted write */ -+ fotg210_readl(fotg210, &fotg210->regs->command); -+} -+ -+/* EHCI timer support... Now using hrtimers. -+ * -+ * Lots of different events are triggered from fotg210->hrtimer. Whenever -+ * the timer routine runs, it checks each possible event; events that are -+ * currently enabled and whose expiration time has passed get handled. -+ * The set of enabled events is stored as a collection of bitflags in -+ * fotg210->enabled_hrtimer_events, and they are numbered in order of -+ * increasing delay values (ranging between 1 ms and 100 ms). -+ * -+ * Rather than implementing a sorted list or tree of all pending events, -+ * we keep track only of the lowest-numbered pending event, in -+ * fotg210->next_hrtimer_event. Whenever fotg210->hrtimer gets restarted, its -+ * expiration time is set to the timeout value for this event. -+ * -+ * As a result, events might not get handled right away; the actual delay -+ * could be anywhere up to twice the requested delay. This doesn't -+ * matter, because none of the events are especially time-critical. The -+ * ones that matter most all have a delay of 1 ms, so they will be -+ * handled after 2 ms at most, which is okay. In addition to this, we -+ * allow for an expiration range of 1 ms. -+ */ -+ -+/* Delay lengths for the hrtimer event types. -+ * Keep this list sorted by delay length, in the same order as -+ * the event types indexed by enum fotg210_hrtimer_event in fotg210.h. -+ */ -+static unsigned event_delays_ns[] = { -+ 1 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_POLL_ASS */ -+ 1 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_POLL_PSS */ -+ 1 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_POLL_DEAD */ -+ 1125 * NSEC_PER_USEC, /* FOTG210_HRTIMER_UNLINK_INTR */ -+ 2 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_FREE_ITDS */ -+ 6 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_ASYNC_UNLINKS */ -+ 10 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_IAA_WATCHDOG */ -+ 10 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_DISABLE_PERIODIC */ -+ 15 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_DISABLE_ASYNC */ -+ 100 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_IO_WATCHDOG */ -+}; -+ -+/* Enable a pending hrtimer event */ -+static void fotg210_enable_event(struct fotg210_hcd *fotg210, unsigned event, -+ bool resched) -+{ -+ ktime_t *timeout = &fotg210->hr_timeouts[event]; -+ -+ if (resched) -+ *timeout = ktime_add(ktime_get(), event_delays_ns[event]); -+ fotg210->enabled_hrtimer_events |= (1 << event); -+ -+ /* Track only the lowest-numbered pending event */ -+ if (event < fotg210->next_hrtimer_event) { -+ fotg210->next_hrtimer_event = event; -+ hrtimer_start_range_ns(&fotg210->hrtimer, *timeout, -+ NSEC_PER_MSEC, HRTIMER_MODE_ABS); -+ } -+} -+ -+ -+/* Poll the STS_ASS status bit; see when it agrees with CMD_ASE */ -+static void fotg210_poll_ASS(struct fotg210_hcd *fotg210) -+{ -+ unsigned actual, want; -+ -+ /* Don't enable anything if the controller isn't running (e.g., died) */ -+ if (fotg210->rh_state != FOTG210_RH_RUNNING) -+ return; -+ -+ want = (fotg210->command & CMD_ASE) ? STS_ASS : 0; -+ actual = fotg210_readl(fotg210, &fotg210->regs->status) & STS_ASS; -+ -+ if (want != actual) { -+ -+ /* Poll again later, but give up after about 20 ms */ -+ if (fotg210->ASS_poll_count++ < 20) { -+ fotg210_enable_event(fotg210, FOTG210_HRTIMER_POLL_ASS, -+ true); -+ return; -+ } -+ fotg210_dbg(fotg210, "Waited too long for the async schedule status (%x/%x), giving up\n", -+ want, actual); -+ } -+ fotg210->ASS_poll_count = 0; -+ -+ /* The status is up-to-date; restart or stop the schedule as needed */ -+ if (want == 0) { /* Stopped */ -+ if (fotg210->async_count > 0) -+ fotg210_set_command_bit(fotg210, CMD_ASE); -+ -+ } else { /* Running */ -+ if (fotg210->async_count == 0) { -+ -+ /* Turn off the schedule after a while */ -+ fotg210_enable_event(fotg210, -+ FOTG210_HRTIMER_DISABLE_ASYNC, -+ true); -+ } -+ } -+} -+ -+/* Turn off the async schedule after a brief delay */ -+static void fotg210_disable_ASE(struct fotg210_hcd *fotg210) -+{ -+ fotg210_clear_command_bit(fotg210, CMD_ASE); -+} -+ -+ -+/* Poll the STS_PSS status bit; see when it agrees with CMD_PSE */ -+static void fotg210_poll_PSS(struct fotg210_hcd *fotg210) -+{ -+ unsigned actual, want; -+ -+ /* Don't do anything if the controller isn't running (e.g., died) */ -+ if (fotg210->rh_state != FOTG210_RH_RUNNING) -+ return; -+ -+ want = (fotg210->command & CMD_PSE) ? STS_PSS : 0; -+ actual = fotg210_readl(fotg210, &fotg210->regs->status) & STS_PSS; -+ -+ if (want != actual) { -+ -+ /* Poll again later, but give up after about 20 ms */ -+ if (fotg210->PSS_poll_count++ < 20) { -+ fotg210_enable_event(fotg210, FOTG210_HRTIMER_POLL_PSS, -+ true); -+ return; -+ } -+ fotg210_dbg(fotg210, "Waited too long for the periodic schedule status (%x/%x), giving up\n", -+ want, actual); -+ } -+ fotg210->PSS_poll_count = 0; -+ -+ /* The status is up-to-date; restart or stop the schedule as needed */ -+ if (want == 0) { /* Stopped */ -+ if (fotg210->periodic_count > 0) -+ fotg210_set_command_bit(fotg210, CMD_PSE); -+ -+ } else { /* Running */ -+ if (fotg210->periodic_count == 0) { -+ -+ /* Turn off the schedule after a while */ -+ fotg210_enable_event(fotg210, -+ FOTG210_HRTIMER_DISABLE_PERIODIC, -+ true); -+ } -+ } -+} -+ -+/* Turn off the periodic schedule after a brief delay */ -+static void fotg210_disable_PSE(struct fotg210_hcd *fotg210) -+{ -+ fotg210_clear_command_bit(fotg210, CMD_PSE); -+} -+ -+ -+/* Poll the STS_HALT status bit; see when a dead controller stops */ -+static void fotg210_handle_controller_death(struct fotg210_hcd *fotg210) -+{ -+ if (!(fotg210_readl(fotg210, &fotg210->regs->status) & STS_HALT)) { -+ -+ /* Give up after a few milliseconds */ -+ if (fotg210->died_poll_count++ < 5) { -+ /* Try again later */ -+ fotg210_enable_event(fotg210, -+ FOTG210_HRTIMER_POLL_DEAD, true); -+ return; -+ } -+ fotg210_warn(fotg210, "Waited too long for the controller to stop, giving up\n"); -+ } -+ -+ /* Clean up the mess */ -+ fotg210->rh_state = FOTG210_RH_HALTED; -+ fotg210_writel(fotg210, 0, &fotg210->regs->intr_enable); -+ fotg210_work(fotg210); -+ end_unlink_async(fotg210); -+ -+ /* Not in process context, so don't try to reset the controller */ -+} -+ -+ -+/* Handle unlinked interrupt QHs once they are gone from the hardware */ -+static void fotg210_handle_intr_unlinks(struct fotg210_hcd *fotg210) -+{ -+ bool stopped = (fotg210->rh_state < FOTG210_RH_RUNNING); -+ -+ /* -+ * Process all the QHs on the intr_unlink list that were added -+ * before the current unlink cycle began. The list is in -+ * temporal order, so stop when we reach the first entry in the -+ * current cycle. But if the root hub isn't running then -+ * process all the QHs on the list. -+ */ -+ fotg210->intr_unlinking = true; -+ while (fotg210->intr_unlink) { -+ struct fotg210_qh *qh = fotg210->intr_unlink; -+ -+ if (!stopped && qh->unlink_cycle == fotg210->intr_unlink_cycle) -+ break; -+ fotg210->intr_unlink = qh->unlink_next; -+ qh->unlink_next = NULL; -+ end_unlink_intr(fotg210, qh); -+ } -+ -+ /* Handle remaining entries later */ -+ if (fotg210->intr_unlink) { -+ fotg210_enable_event(fotg210, FOTG210_HRTIMER_UNLINK_INTR, -+ true); -+ ++fotg210->intr_unlink_cycle; -+ } -+ fotg210->intr_unlinking = false; -+} -+ -+ -+/* Start another free-iTDs/siTDs cycle */ -+static void start_free_itds(struct fotg210_hcd *fotg210) -+{ -+ if (!(fotg210->enabled_hrtimer_events & -+ BIT(FOTG210_HRTIMER_FREE_ITDS))) { -+ fotg210->last_itd_to_free = list_entry( -+ fotg210->cached_itd_list.prev, -+ struct fotg210_itd, itd_list); -+ fotg210_enable_event(fotg210, FOTG210_HRTIMER_FREE_ITDS, true); -+ } -+} -+ -+/* Wait for controller to stop using old iTDs and siTDs */ -+static void end_free_itds(struct fotg210_hcd *fotg210) -+{ -+ struct fotg210_itd *itd, *n; -+ -+ if (fotg210->rh_state < FOTG210_RH_RUNNING) -+ fotg210->last_itd_to_free = NULL; -+ -+ list_for_each_entry_safe(itd, n, &fotg210->cached_itd_list, itd_list) { -+ list_del(&itd->itd_list); -+ dma_pool_free(fotg210->itd_pool, itd, itd->itd_dma); -+ if (itd == fotg210->last_itd_to_free) -+ break; -+ } -+ -+ if (!list_empty(&fotg210->cached_itd_list)) -+ start_free_itds(fotg210); -+} -+ -+ -+/* Handle lost (or very late) IAA interrupts */ -+static void fotg210_iaa_watchdog(struct fotg210_hcd *fotg210) -+{ -+ if (fotg210->rh_state != FOTG210_RH_RUNNING) -+ return; -+ -+ /* -+ * Lost IAA irqs wedge things badly; seen first with a vt8235. -+ * So we need this watchdog, but must protect it against both -+ * (a) SMP races against real IAA firing and retriggering, and -+ * (b) clean HC shutdown, when IAA watchdog was pending. -+ */ -+ if (fotg210->async_iaa) { -+ u32 cmd, status; -+ -+ /* If we get here, IAA is *REALLY* late. It's barely -+ * conceivable that the system is so busy that CMD_IAAD -+ * is still legitimately set, so let's be sure it's -+ * clear before we read STS_IAA. (The HC should clear -+ * CMD_IAAD when it sets STS_IAA.) -+ */ -+ cmd = fotg210_readl(fotg210, &fotg210->regs->command); -+ -+ /* -+ * If IAA is set here it either legitimately triggered -+ * after the watchdog timer expired (_way_ late, so we'll -+ * still count it as lost) ... or a silicon erratum: -+ * - VIA seems to set IAA without triggering the IRQ; -+ * - IAAD potentially cleared without setting IAA. -+ */ -+ status = fotg210_readl(fotg210, &fotg210->regs->status); -+ if ((status & STS_IAA) || !(cmd & CMD_IAAD)) { -+ INCR(fotg210->stats.lost_iaa); -+ fotg210_writel(fotg210, STS_IAA, -+ &fotg210->regs->status); -+ } -+ -+ fotg210_dbg(fotg210, "IAA watchdog: status %x cmd %x\n", -+ status, cmd); -+ end_unlink_async(fotg210); -+ } -+} -+ -+ -+/* Enable the I/O watchdog, if appropriate */ -+static void turn_on_io_watchdog(struct fotg210_hcd *fotg210) -+{ -+ /* Not needed if the controller isn't running or it's already enabled */ -+ if (fotg210->rh_state != FOTG210_RH_RUNNING || -+ (fotg210->enabled_hrtimer_events & -+ BIT(FOTG210_HRTIMER_IO_WATCHDOG))) -+ return; -+ -+ /* -+ * Isochronous transfers always need the watchdog. -+ * For other sorts we use it only if the flag is set. -+ */ -+ if (fotg210->isoc_count > 0 || (fotg210->need_io_watchdog && -+ fotg210->async_count + fotg210->intr_count > 0)) -+ fotg210_enable_event(fotg210, FOTG210_HRTIMER_IO_WATCHDOG, -+ true); -+} -+ -+ -+/* Handler functions for the hrtimer event types. -+ * Keep this array in the same order as the event types indexed by -+ * enum fotg210_hrtimer_event in fotg210.h. -+ */ -+static void (*event_handlers[])(struct fotg210_hcd *) = { -+ fotg210_poll_ASS, /* FOTG210_HRTIMER_POLL_ASS */ -+ fotg210_poll_PSS, /* FOTG210_HRTIMER_POLL_PSS */ -+ fotg210_handle_controller_death, /* FOTG210_HRTIMER_POLL_DEAD */ -+ fotg210_handle_intr_unlinks, /* FOTG210_HRTIMER_UNLINK_INTR */ -+ end_free_itds, /* FOTG210_HRTIMER_FREE_ITDS */ -+ unlink_empty_async, /* FOTG210_HRTIMER_ASYNC_UNLINKS */ -+ fotg210_iaa_watchdog, /* FOTG210_HRTIMER_IAA_WATCHDOG */ -+ fotg210_disable_PSE, /* FOTG210_HRTIMER_DISABLE_PERIODIC */ -+ fotg210_disable_ASE, /* FOTG210_HRTIMER_DISABLE_ASYNC */ -+ fotg210_work, /* FOTG210_HRTIMER_IO_WATCHDOG */ -+}; -+ -+static enum hrtimer_restart fotg210_hrtimer_func(struct hrtimer *t) -+{ -+ struct fotg210_hcd *fotg210 = -+ container_of(t, struct fotg210_hcd, hrtimer); -+ ktime_t now; -+ unsigned long events; -+ unsigned long flags; -+ unsigned e; -+ -+ spin_lock_irqsave(&fotg210->lock, flags); -+ -+ events = fotg210->enabled_hrtimer_events; -+ fotg210->enabled_hrtimer_events = 0; -+ fotg210->next_hrtimer_event = FOTG210_HRTIMER_NO_EVENT; -+ -+ /* -+ * Check each pending event. If its time has expired, handle -+ * the event; otherwise re-enable it. -+ */ -+ now = ktime_get(); -+ for_each_set_bit(e, &events, FOTG210_HRTIMER_NUM_EVENTS) { -+ if (ktime_compare(now, fotg210->hr_timeouts[e]) >= 0) -+ event_handlers[e](fotg210); -+ else -+ fotg210_enable_event(fotg210, e, false); -+ } -+ -+ spin_unlock_irqrestore(&fotg210->lock, flags); -+ return HRTIMER_NORESTART; -+} -+ -+#define fotg210_bus_suspend NULL -+#define fotg210_bus_resume NULL -+ -+static int check_reset_complete(struct fotg210_hcd *fotg210, int index, -+ u32 __iomem *status_reg, int port_status) -+{ -+ if (!(port_status & PORT_CONNECT)) -+ return port_status; -+ -+ /* if reset finished and it's still not enabled -- handoff */ -+ if (!(port_status & PORT_PE)) -+ /* with integrated TT, there's nobody to hand it to! */ -+ fotg210_dbg(fotg210, "Failed to enable port %d on root hub TT\n", -+ index + 1); -+ else -+ fotg210_dbg(fotg210, "port %d reset complete, port enabled\n", -+ index + 1); -+ -+ return port_status; -+} -+ -+ -+/* build "status change" packet (one or two bytes) from HC registers */ -+ -+static int fotg210_hub_status_data(struct usb_hcd *hcd, char *buf) -+{ -+ struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); -+ u32 temp, status; -+ u32 mask; -+ int retval = 1; -+ unsigned long flags; -+ -+ /* init status to no-changes */ -+ buf[0] = 0; -+ -+ /* Inform the core about resumes-in-progress by returning -+ * a non-zero value even if there are no status changes. -+ */ -+ status = fotg210->resuming_ports; -+ -+ mask = PORT_CSC | PORT_PEC; -+ /* PORT_RESUME from hardware ~= PORT_STAT_C_SUSPEND */ -+ -+ /* no hub change reports (bit 0) for now (power, ...) */ -+ -+ /* port N changes (bit N)? */ -+ spin_lock_irqsave(&fotg210->lock, flags); -+ -+ temp = fotg210_readl(fotg210, &fotg210->regs->port_status); -+ -+ /* -+ * Return status information even for ports with OWNER set. -+ * Otherwise hub_wq wouldn't see the disconnect event when a -+ * high-speed device is switched over to the companion -+ * controller by the user. -+ */ -+ -+ if ((temp & mask) != 0 || test_bit(0, &fotg210->port_c_suspend) || -+ (fotg210->reset_done[0] && -+ time_after_eq(jiffies, fotg210->reset_done[0]))) { -+ buf[0] |= 1 << 1; -+ status = STS_PCD; -+ } -+ /* FIXME autosuspend idle root hubs */ -+ spin_unlock_irqrestore(&fotg210->lock, flags); -+ return status ? retval : 0; -+} -+ -+static void fotg210_hub_descriptor(struct fotg210_hcd *fotg210, -+ struct usb_hub_descriptor *desc) -+{ -+ int ports = HCS_N_PORTS(fotg210->hcs_params); -+ u16 temp; -+ -+ desc->bDescriptorType = USB_DT_HUB; -+ desc->bPwrOn2PwrGood = 10; /* fotg210 1.0, 2.3.9 says 20ms max */ -+ desc->bHubContrCurrent = 0; -+ -+ desc->bNbrPorts = ports; -+ temp = 1 + (ports / 8); -+ desc->bDescLength = 7 + 2 * temp; -+ -+ /* two bitmaps: ports removable, and usb 1.0 legacy PortPwrCtrlMask */ -+ memset(&desc->u.hs.DeviceRemovable[0], 0, temp); -+ memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp); -+ -+ temp = HUB_CHAR_INDV_PORT_OCPM; /* per-port overcurrent reporting */ -+ temp |= HUB_CHAR_NO_LPSM; /* no power switching */ -+ desc->wHubCharacteristics = cpu_to_le16(temp); -+} -+ -+static int fotg210_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, -+ u16 wIndex, char *buf, u16 wLength) -+{ -+ struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); -+ int ports = HCS_N_PORTS(fotg210->hcs_params); -+ u32 __iomem *status_reg = &fotg210->regs->port_status; -+ u32 temp, temp1, status; -+ unsigned long flags; -+ int retval = 0; -+ unsigned selector; -+ -+ /* -+ * FIXME: support SetPortFeatures USB_PORT_FEAT_INDICATOR. -+ * HCS_INDICATOR may say we can change LEDs to off/amber/green. -+ * (track current state ourselves) ... blink for diagnostics, -+ * power, "this is the one", etc. EHCI spec supports this. -+ */ -+ -+ spin_lock_irqsave(&fotg210->lock, flags); -+ switch (typeReq) { -+ case ClearHubFeature: -+ switch (wValue) { -+ case C_HUB_LOCAL_POWER: -+ case C_HUB_OVER_CURRENT: -+ /* no hub-wide feature/status flags */ -+ break; -+ default: -+ goto error; -+ } -+ break; -+ case ClearPortFeature: -+ if (!wIndex || wIndex > ports) -+ goto error; -+ wIndex--; -+ temp = fotg210_readl(fotg210, status_reg); -+ temp &= ~PORT_RWC_BITS; -+ -+ /* -+ * Even if OWNER is set, so the port is owned by the -+ * companion controller, hub_wq needs to be able to clear -+ * the port-change status bits (especially -+ * USB_PORT_STAT_C_CONNECTION). -+ */ -+ -+ switch (wValue) { -+ case USB_PORT_FEAT_ENABLE: -+ fotg210_writel(fotg210, temp & ~PORT_PE, status_reg); -+ break; -+ case USB_PORT_FEAT_C_ENABLE: -+ fotg210_writel(fotg210, temp | PORT_PEC, status_reg); -+ break; -+ case USB_PORT_FEAT_SUSPEND: -+ if (temp & PORT_RESET) -+ goto error; -+ if (!(temp & PORT_SUSPEND)) -+ break; -+ if ((temp & PORT_PE) == 0) -+ goto error; -+ -+ /* resume signaling for 20 msec */ -+ fotg210_writel(fotg210, temp | PORT_RESUME, status_reg); -+ fotg210->reset_done[wIndex] = jiffies -+ + msecs_to_jiffies(USB_RESUME_TIMEOUT); -+ break; -+ case USB_PORT_FEAT_C_SUSPEND: -+ clear_bit(wIndex, &fotg210->port_c_suspend); -+ break; -+ case USB_PORT_FEAT_C_CONNECTION: -+ fotg210_writel(fotg210, temp | PORT_CSC, status_reg); -+ break; -+ case USB_PORT_FEAT_C_OVER_CURRENT: -+ fotg210_writel(fotg210, temp | OTGISR_OVC, -+ &fotg210->regs->otgisr); -+ break; -+ case USB_PORT_FEAT_C_RESET: -+ /* GetPortStatus clears reset */ -+ break; -+ default: -+ goto error; -+ } -+ fotg210_readl(fotg210, &fotg210->regs->command); -+ break; -+ case GetHubDescriptor: -+ fotg210_hub_descriptor(fotg210, (struct usb_hub_descriptor *) -+ buf); -+ break; -+ case GetHubStatus: -+ /* no hub-wide feature/status flags */ -+ memset(buf, 0, 4); -+ /*cpu_to_le32s ((u32 *) buf); */ -+ break; -+ case GetPortStatus: -+ if (!wIndex || wIndex > ports) -+ goto error; -+ wIndex--; -+ status = 0; -+ temp = fotg210_readl(fotg210, status_reg); -+ -+ /* wPortChange bits */ -+ if (temp & PORT_CSC) -+ status |= USB_PORT_STAT_C_CONNECTION << 16; -+ if (temp & PORT_PEC) -+ status |= USB_PORT_STAT_C_ENABLE << 16; -+ -+ temp1 = fotg210_readl(fotg210, &fotg210->regs->otgisr); -+ if (temp1 & OTGISR_OVC) -+ status |= USB_PORT_STAT_C_OVERCURRENT << 16; -+ -+ /* whoever resumes must GetPortStatus to complete it!! */ -+ if (temp & PORT_RESUME) { -+ -+ /* Remote Wakeup received? */ -+ if (!fotg210->reset_done[wIndex]) { -+ /* resume signaling for 20 msec */ -+ fotg210->reset_done[wIndex] = jiffies -+ + msecs_to_jiffies(20); -+ /* check the port again */ -+ mod_timer(&fotg210_to_hcd(fotg210)->rh_timer, -+ fotg210->reset_done[wIndex]); -+ } -+ -+ /* resume completed? */ -+ else if (time_after_eq(jiffies, -+ fotg210->reset_done[wIndex])) { -+ clear_bit(wIndex, &fotg210->suspended_ports); -+ set_bit(wIndex, &fotg210->port_c_suspend); -+ fotg210->reset_done[wIndex] = 0; -+ -+ /* stop resume signaling */ -+ temp = fotg210_readl(fotg210, status_reg); -+ fotg210_writel(fotg210, temp & -+ ~(PORT_RWC_BITS | PORT_RESUME), -+ status_reg); -+ clear_bit(wIndex, &fotg210->resuming_ports); -+ retval = handshake(fotg210, status_reg, -+ PORT_RESUME, 0, 2000);/* 2ms */ -+ if (retval != 0) { -+ fotg210_err(fotg210, -+ "port %d resume error %d\n", -+ wIndex + 1, retval); -+ goto error; -+ } -+ temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10)); -+ } -+ } -+ -+ /* whoever resets must GetPortStatus to complete it!! */ -+ if ((temp & PORT_RESET) && time_after_eq(jiffies, -+ fotg210->reset_done[wIndex])) { -+ status |= USB_PORT_STAT_C_RESET << 16; -+ fotg210->reset_done[wIndex] = 0; -+ clear_bit(wIndex, &fotg210->resuming_ports); -+ -+ /* force reset to complete */ -+ fotg210_writel(fotg210, -+ temp & ~(PORT_RWC_BITS | PORT_RESET), -+ status_reg); -+ /* REVISIT: some hardware needs 550+ usec to clear -+ * this bit; seems too long to spin routinely... -+ */ -+ retval = handshake(fotg210, status_reg, -+ PORT_RESET, 0, 1000); -+ if (retval != 0) { -+ fotg210_err(fotg210, "port %d reset error %d\n", -+ wIndex + 1, retval); -+ goto error; -+ } -+ -+ /* see what we found out */ -+ temp = check_reset_complete(fotg210, wIndex, status_reg, -+ fotg210_readl(fotg210, status_reg)); -+ -+ /* restart schedule */ -+ fotg210->command |= CMD_RUN; -+ fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command); -+ } -+ -+ if (!(temp & (PORT_RESUME|PORT_RESET))) { -+ fotg210->reset_done[wIndex] = 0; -+ clear_bit(wIndex, &fotg210->resuming_ports); -+ } -+ -+ /* transfer dedicated ports to the companion hc */ -+ if ((temp & PORT_CONNECT) && -+ test_bit(wIndex, &fotg210->companion_ports)) { -+ temp &= ~PORT_RWC_BITS; -+ fotg210_writel(fotg210, temp, status_reg); -+ fotg210_dbg(fotg210, "port %d --> companion\n", -+ wIndex + 1); -+ temp = fotg210_readl(fotg210, status_reg); -+ } -+ -+ /* -+ * Even if OWNER is set, there's no harm letting hub_wq -+ * see the wPortStatus values (they should all be 0 except -+ * for PORT_POWER anyway). -+ */ -+ -+ if (temp & PORT_CONNECT) { -+ status |= USB_PORT_STAT_CONNECTION; -+ status |= fotg210_port_speed(fotg210, temp); -+ } -+ if (temp & PORT_PE) -+ status |= USB_PORT_STAT_ENABLE; -+ -+ /* maybe the port was unsuspended without our knowledge */ -+ if (temp & (PORT_SUSPEND|PORT_RESUME)) { -+ status |= USB_PORT_STAT_SUSPEND; -+ } else if (test_bit(wIndex, &fotg210->suspended_ports)) { -+ clear_bit(wIndex, &fotg210->suspended_ports); -+ clear_bit(wIndex, &fotg210->resuming_ports); -+ fotg210->reset_done[wIndex] = 0; -+ if (temp & PORT_PE) -+ set_bit(wIndex, &fotg210->port_c_suspend); -+ } -+ -+ temp1 = fotg210_readl(fotg210, &fotg210->regs->otgisr); -+ if (temp1 & OTGISR_OVC) -+ status |= USB_PORT_STAT_OVERCURRENT; -+ if (temp & PORT_RESET) -+ status |= USB_PORT_STAT_RESET; -+ if (test_bit(wIndex, &fotg210->port_c_suspend)) -+ status |= USB_PORT_STAT_C_SUSPEND << 16; -+ -+ if (status & ~0xffff) /* only if wPortChange is interesting */ -+ dbg_port(fotg210, "GetStatus", wIndex + 1, temp); -+ put_unaligned_le32(status, buf); -+ break; -+ case SetHubFeature: -+ switch (wValue) { -+ case C_HUB_LOCAL_POWER: -+ case C_HUB_OVER_CURRENT: -+ /* no hub-wide feature/status flags */ -+ break; -+ default: -+ goto error; -+ } -+ break; -+ case SetPortFeature: -+ selector = wIndex >> 8; -+ wIndex &= 0xff; -+ -+ if (!wIndex || wIndex > ports) -+ goto error; -+ wIndex--; -+ temp = fotg210_readl(fotg210, status_reg); -+ temp &= ~PORT_RWC_BITS; -+ switch (wValue) { -+ case USB_PORT_FEAT_SUSPEND: -+ if ((temp & PORT_PE) == 0 -+ || (temp & PORT_RESET) != 0) -+ goto error; -+ -+ /* After above check the port must be connected. -+ * Set appropriate bit thus could put phy into low power -+ * mode if we have hostpc feature -+ */ -+ fotg210_writel(fotg210, temp | PORT_SUSPEND, -+ status_reg); -+ set_bit(wIndex, &fotg210->suspended_ports); -+ break; -+ case USB_PORT_FEAT_RESET: -+ if (temp & PORT_RESUME) -+ goto error; -+ /* line status bits may report this as low speed, -+ * which can be fine if this root hub has a -+ * transaction translator built in. -+ */ -+ fotg210_dbg(fotg210, "port %d reset\n", wIndex + 1); -+ temp |= PORT_RESET; -+ temp &= ~PORT_PE; -+ -+ /* -+ * caller must wait, then call GetPortStatus -+ * usb 2.0 spec says 50 ms resets on root -+ */ -+ fotg210->reset_done[wIndex] = jiffies -+ + msecs_to_jiffies(50); -+ fotg210_writel(fotg210, temp, status_reg); -+ break; -+ -+ /* For downstream facing ports (these): one hub port is put -+ * into test mode according to USB2 11.24.2.13, then the hub -+ * must be reset (which for root hub now means rmmod+modprobe, -+ * or else system reboot). See EHCI 2.3.9 and 4.14 for info -+ * about the EHCI-specific stuff. -+ */ -+ case USB_PORT_FEAT_TEST: -+ if (!selector || selector > 5) -+ goto error; -+ spin_unlock_irqrestore(&fotg210->lock, flags); -+ fotg210_quiesce(fotg210); -+ spin_lock_irqsave(&fotg210->lock, flags); -+ -+ /* Put all enabled ports into suspend */ -+ temp = fotg210_readl(fotg210, status_reg) & -+ ~PORT_RWC_BITS; -+ if (temp & PORT_PE) -+ fotg210_writel(fotg210, temp | PORT_SUSPEND, -+ status_reg); -+ -+ spin_unlock_irqrestore(&fotg210->lock, flags); -+ fotg210_halt(fotg210); -+ spin_lock_irqsave(&fotg210->lock, flags); -+ -+ temp = fotg210_readl(fotg210, status_reg); -+ temp |= selector << 16; -+ fotg210_writel(fotg210, temp, status_reg); -+ break; -+ -+ default: -+ goto error; -+ } -+ fotg210_readl(fotg210, &fotg210->regs->command); -+ break; -+ -+ default: -+error: -+ /* "stall" on error */ -+ retval = -EPIPE; -+ } -+ spin_unlock_irqrestore(&fotg210->lock, flags); -+ return retval; -+} -+ -+static void __maybe_unused fotg210_relinquish_port(struct usb_hcd *hcd, -+ int portnum) -+{ -+ return; -+} -+ -+static int __maybe_unused fotg210_port_handed_over(struct usb_hcd *hcd, -+ int portnum) -+{ -+ return 0; -+} -+ -+/* There's basically three types of memory: -+ * - data used only by the HCD ... kmalloc is fine -+ * - async and periodic schedules, shared by HC and HCD ... these -+ * need to use dma_pool or dma_alloc_coherent -+ * - driver buffers, read/written by HC ... single shot DMA mapped -+ * -+ * There's also "register" data (e.g. PCI or SOC), which is memory mapped. -+ * No memory seen by this driver is pageable. -+ */ -+ -+/* Allocate the key transfer structures from the previously allocated pool */ -+static inline void fotg210_qtd_init(struct fotg210_hcd *fotg210, -+ struct fotg210_qtd *qtd, dma_addr_t dma) -+{ -+ memset(qtd, 0, sizeof(*qtd)); -+ qtd->qtd_dma = dma; -+ qtd->hw_token = cpu_to_hc32(fotg210, QTD_STS_HALT); -+ qtd->hw_next = FOTG210_LIST_END(fotg210); -+ qtd->hw_alt_next = FOTG210_LIST_END(fotg210); -+ INIT_LIST_HEAD(&qtd->qtd_list); -+} -+ -+static struct fotg210_qtd *fotg210_qtd_alloc(struct fotg210_hcd *fotg210, -+ gfp_t flags) -+{ -+ struct fotg210_qtd *qtd; -+ dma_addr_t dma; -+ -+ qtd = dma_pool_alloc(fotg210->qtd_pool, flags, &dma); -+ if (qtd != NULL) -+ fotg210_qtd_init(fotg210, qtd, dma); -+ -+ return qtd; -+} -+ -+static inline void fotg210_qtd_free(struct fotg210_hcd *fotg210, -+ struct fotg210_qtd *qtd) -+{ -+ dma_pool_free(fotg210->qtd_pool, qtd, qtd->qtd_dma); -+} -+ -+ -+static void qh_destroy(struct fotg210_hcd *fotg210, struct fotg210_qh *qh) -+{ -+ /* clean qtds first, and know this is not linked */ -+ if (!list_empty(&qh->qtd_list) || qh->qh_next.ptr) { -+ fotg210_dbg(fotg210, "unused qh not empty!\n"); -+ BUG(); -+ } -+ if (qh->dummy) -+ fotg210_qtd_free(fotg210, qh->dummy); -+ dma_pool_free(fotg210->qh_pool, qh->hw, qh->qh_dma); -+ kfree(qh); -+} -+ -+static struct fotg210_qh *fotg210_qh_alloc(struct fotg210_hcd *fotg210, -+ gfp_t flags) -+{ -+ struct fotg210_qh *qh; -+ dma_addr_t dma; -+ -+ qh = kzalloc(sizeof(*qh), GFP_ATOMIC); -+ if (!qh) -+ goto done; -+ qh->hw = (struct fotg210_qh_hw *) -+ dma_pool_zalloc(fotg210->qh_pool, flags, &dma); -+ if (!qh->hw) -+ goto fail; -+ qh->qh_dma = dma; -+ INIT_LIST_HEAD(&qh->qtd_list); -+ -+ /* dummy td enables safe urb queuing */ -+ qh->dummy = fotg210_qtd_alloc(fotg210, flags); -+ if (qh->dummy == NULL) { -+ fotg210_dbg(fotg210, "no dummy td\n"); -+ goto fail1; -+ } -+done: -+ return qh; -+fail1: -+ dma_pool_free(fotg210->qh_pool, qh->hw, qh->qh_dma); -+fail: -+ kfree(qh); -+ return NULL; -+} -+ -+/* The queue heads and transfer descriptors are managed from pools tied -+ * to each of the "per device" structures. -+ * This is the initialisation and cleanup code. -+ */ -+ -+static void fotg210_mem_cleanup(struct fotg210_hcd *fotg210) -+{ -+ if (fotg210->async) -+ qh_destroy(fotg210, fotg210->async); -+ fotg210->async = NULL; -+ -+ if (fotg210->dummy) -+ qh_destroy(fotg210, fotg210->dummy); -+ fotg210->dummy = NULL; -+ -+ /* DMA consistent memory and pools */ -+ dma_pool_destroy(fotg210->qtd_pool); -+ fotg210->qtd_pool = NULL; -+ -+ dma_pool_destroy(fotg210->qh_pool); -+ fotg210->qh_pool = NULL; -+ -+ dma_pool_destroy(fotg210->itd_pool); -+ fotg210->itd_pool = NULL; -+ -+ if (fotg210->periodic) -+ dma_free_coherent(fotg210_to_hcd(fotg210)->self.controller, -+ fotg210->periodic_size * sizeof(u32), -+ fotg210->periodic, fotg210->periodic_dma); -+ fotg210->periodic = NULL; -+ -+ /* shadow periodic table */ -+ kfree(fotg210->pshadow); -+ fotg210->pshadow = NULL; -+} -+ -+/* remember to add cleanup code (above) if you add anything here */ -+static int fotg210_mem_init(struct fotg210_hcd *fotg210, gfp_t flags) -+{ -+ int i; -+ -+ /* QTDs for control/bulk/intr transfers */ -+ fotg210->qtd_pool = dma_pool_create("fotg210_qtd", -+ fotg210_to_hcd(fotg210)->self.controller, -+ sizeof(struct fotg210_qtd), -+ 32 /* byte alignment (for hw parts) */, -+ 4096 /* can't cross 4K */); -+ if (!fotg210->qtd_pool) -+ goto fail; -+ -+ /* QHs for control/bulk/intr transfers */ -+ fotg210->qh_pool = dma_pool_create("fotg210_qh", -+ fotg210_to_hcd(fotg210)->self.controller, -+ sizeof(struct fotg210_qh_hw), -+ 32 /* byte alignment (for hw parts) */, -+ 4096 /* can't cross 4K */); -+ if (!fotg210->qh_pool) -+ goto fail; -+ -+ fotg210->async = fotg210_qh_alloc(fotg210, flags); -+ if (!fotg210->async) -+ goto fail; -+ -+ /* ITD for high speed ISO transfers */ -+ fotg210->itd_pool = dma_pool_create("fotg210_itd", -+ fotg210_to_hcd(fotg210)->self.controller, -+ sizeof(struct fotg210_itd), -+ 64 /* byte alignment (for hw parts) */, -+ 4096 /* can't cross 4K */); -+ if (!fotg210->itd_pool) -+ goto fail; -+ -+ /* Hardware periodic table */ -+ fotg210->periodic = -+ dma_alloc_coherent(fotg210_to_hcd(fotg210)->self.controller, -+ fotg210->periodic_size * sizeof(__le32), -+ &fotg210->periodic_dma, 0); -+ if (fotg210->periodic == NULL) -+ goto fail; -+ -+ for (i = 0; i < fotg210->periodic_size; i++) -+ fotg210->periodic[i] = FOTG210_LIST_END(fotg210); -+ -+ /* software shadow of hardware table */ -+ fotg210->pshadow = kcalloc(fotg210->periodic_size, sizeof(void *), -+ flags); -+ if (fotg210->pshadow != NULL) -+ return 0; -+ -+fail: -+ fotg210_dbg(fotg210, "couldn't init memory\n"); -+ fotg210_mem_cleanup(fotg210); -+ return -ENOMEM; -+} -+/* EHCI hardware queue manipulation ... the core. QH/QTD manipulation. -+ * -+ * Control, bulk, and interrupt traffic all use "qh" lists. They list "qtd" -+ * entries describing USB transactions, max 16-20kB/entry (with 4kB-aligned -+ * buffers needed for the larger number). We use one QH per endpoint, queue -+ * multiple urbs (all three types) per endpoint. URBs may need several qtds. -+ * -+ * ISO traffic uses "ISO TD" (itd) records, and (along with -+ * interrupts) needs careful scheduling. Performance improvements can be -+ * an ongoing challenge. That's in "ehci-sched.c". -+ * -+ * USB 1.1 devices are handled (a) by "companion" OHCI or UHCI root hubs, -+ * or otherwise through transaction translators (TTs) in USB 2.0 hubs using -+ * (b) special fields in qh entries or (c) split iso entries. TTs will -+ * buffer low/full speed data so the host collects it at high speed. -+ */ -+ -+/* fill a qtd, returning how much of the buffer we were able to queue up */ -+static int qtd_fill(struct fotg210_hcd *fotg210, struct fotg210_qtd *qtd, -+ dma_addr_t buf, size_t len, int token, int maxpacket) -+{ -+ int i, count; -+ u64 addr = buf; -+ -+ /* one buffer entry per 4K ... first might be short or unaligned */ -+ qtd->hw_buf[0] = cpu_to_hc32(fotg210, (u32)addr); -+ qtd->hw_buf_hi[0] = cpu_to_hc32(fotg210, (u32)(addr >> 32)); -+ count = 0x1000 - (buf & 0x0fff); /* rest of that page */ -+ if (likely(len < count)) /* ... iff needed */ -+ count = len; -+ else { -+ buf += 0x1000; -+ buf &= ~0x0fff; -+ -+ /* per-qtd limit: from 16K to 20K (best alignment) */ -+ for (i = 1; count < len && i < 5; i++) { -+ addr = buf; -+ qtd->hw_buf[i] = cpu_to_hc32(fotg210, (u32)addr); -+ qtd->hw_buf_hi[i] = cpu_to_hc32(fotg210, -+ (u32)(addr >> 32)); -+ buf += 0x1000; -+ if ((count + 0x1000) < len) -+ count += 0x1000; -+ else -+ count = len; -+ } -+ -+ /* short packets may only terminate transfers */ -+ if (count != len) -+ count -= (count % maxpacket); -+ } -+ qtd->hw_token = cpu_to_hc32(fotg210, (count << 16) | token); -+ qtd->length = count; -+ -+ return count; -+} -+ -+static inline void qh_update(struct fotg210_hcd *fotg210, -+ struct fotg210_qh *qh, struct fotg210_qtd *qtd) -+{ -+ struct fotg210_qh_hw *hw = qh->hw; -+ -+ /* writes to an active overlay are unsafe */ -+ BUG_ON(qh->qh_state != QH_STATE_IDLE); -+ -+ hw->hw_qtd_next = QTD_NEXT(fotg210, qtd->qtd_dma); -+ hw->hw_alt_next = FOTG210_LIST_END(fotg210); -+ -+ /* Except for control endpoints, we make hardware maintain data -+ * toggle (like OHCI) ... here (re)initialize the toggle in the QH, -+ * and set the pseudo-toggle in udev. Only usb_clear_halt() will -+ * ever clear it. -+ */ -+ if (!(hw->hw_info1 & cpu_to_hc32(fotg210, QH_TOGGLE_CTL))) { -+ unsigned is_out, epnum; -+ -+ is_out = qh->is_out; -+ epnum = (hc32_to_cpup(fotg210, &hw->hw_info1) >> 8) & 0x0f; -+ if (unlikely(!usb_gettoggle(qh->dev, epnum, is_out))) { -+ hw->hw_token &= ~cpu_to_hc32(fotg210, QTD_TOGGLE); -+ usb_settoggle(qh->dev, epnum, is_out, 1); -+ } -+ } -+ -+ hw->hw_token &= cpu_to_hc32(fotg210, QTD_TOGGLE | QTD_STS_PING); -+} -+ -+/* if it weren't for a common silicon quirk (writing the dummy into the qh -+ * overlay, so qh->hw_token wrongly becomes inactive/halted), only fault -+ * recovery (including urb dequeue) would need software changes to a QH... -+ */ -+static void qh_refresh(struct fotg210_hcd *fotg210, struct fotg210_qh *qh) -+{ -+ struct fotg210_qtd *qtd; -+ -+ if (list_empty(&qh->qtd_list)) -+ qtd = qh->dummy; -+ else { -+ qtd = list_entry(qh->qtd_list.next, -+ struct fotg210_qtd, qtd_list); -+ /* -+ * first qtd may already be partially processed. -+ * If we come here during unlink, the QH overlay region -+ * might have reference to the just unlinked qtd. The -+ * qtd is updated in qh_completions(). Update the QH -+ * overlay here. -+ */ -+ if (cpu_to_hc32(fotg210, qtd->qtd_dma) == qh->hw->hw_current) { -+ qh->hw->hw_qtd_next = qtd->hw_next; -+ qtd = NULL; -+ } -+ } -+ -+ if (qtd) -+ qh_update(fotg210, qh, qtd); -+} -+ -+static void qh_link_async(struct fotg210_hcd *fotg210, struct fotg210_qh *qh); -+ -+static void fotg210_clear_tt_buffer_complete(struct usb_hcd *hcd, -+ struct usb_host_endpoint *ep) -+{ -+ struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); -+ struct fotg210_qh *qh = ep->hcpriv; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&fotg210->lock, flags); -+ qh->clearing_tt = 0; -+ if (qh->qh_state == QH_STATE_IDLE && !list_empty(&qh->qtd_list) -+ && fotg210->rh_state == FOTG210_RH_RUNNING) -+ qh_link_async(fotg210, qh); -+ spin_unlock_irqrestore(&fotg210->lock, flags); -+} -+ -+static void fotg210_clear_tt_buffer(struct fotg210_hcd *fotg210, -+ struct fotg210_qh *qh, struct urb *urb, u32 token) -+{ -+ -+ /* If an async split transaction gets an error or is unlinked, -+ * the TT buffer may be left in an indeterminate state. We -+ * have to clear the TT buffer. -+ * -+ * Note: this routine is never called for Isochronous transfers. -+ */ -+ if (urb->dev->tt && !usb_pipeint(urb->pipe) && !qh->clearing_tt) { -+ struct usb_device *tt = urb->dev->tt->hub; -+ -+ dev_dbg(&tt->dev, -+ "clear tt buffer port %d, a%d ep%d t%08x\n", -+ urb->dev->ttport, urb->dev->devnum, -+ usb_pipeendpoint(urb->pipe), token); -+ -+ if (urb->dev->tt->hub != -+ fotg210_to_hcd(fotg210)->self.root_hub) { -+ if (usb_hub_clear_tt_buffer(urb) == 0) -+ qh->clearing_tt = 1; -+ } -+ } -+} -+ -+static int qtd_copy_status(struct fotg210_hcd *fotg210, struct urb *urb, -+ size_t length, u32 token) -+{ -+ int status = -EINPROGRESS; -+ -+ /* count IN/OUT bytes, not SETUP (even short packets) */ -+ if (likely(QTD_PID(token) != 2)) -+ urb->actual_length += length - QTD_LENGTH(token); -+ -+ /* don't modify error codes */ -+ if (unlikely(urb->unlinked)) -+ return status; -+ -+ /* force cleanup after short read; not always an error */ -+ if (unlikely(IS_SHORT_READ(token))) -+ status = -EREMOTEIO; -+ -+ /* serious "can't proceed" faults reported by the hardware */ -+ if (token & QTD_STS_HALT) { -+ if (token & QTD_STS_BABBLE) { -+ /* FIXME "must" disable babbling device's port too */ -+ status = -EOVERFLOW; -+ /* CERR nonzero + halt --> stall */ -+ } else if (QTD_CERR(token)) { -+ status = -EPIPE; -+ -+ /* In theory, more than one of the following bits can be set -+ * since they are sticky and the transaction is retried. -+ * Which to test first is rather arbitrary. -+ */ -+ } else if (token & QTD_STS_MMF) { -+ /* fs/ls interrupt xfer missed the complete-split */ -+ status = -EPROTO; -+ } else if (token & QTD_STS_DBE) { -+ status = (QTD_PID(token) == 1) /* IN ? */ -+ ? -ENOSR /* hc couldn't read data */ -+ : -ECOMM; /* hc couldn't write data */ -+ } else if (token & QTD_STS_XACT) { -+ /* timeout, bad CRC, wrong PID, etc */ -+ fotg210_dbg(fotg210, "devpath %s ep%d%s 3strikes\n", -+ urb->dev->devpath, -+ usb_pipeendpoint(urb->pipe), -+ usb_pipein(urb->pipe) ? "in" : "out"); -+ status = -EPROTO; -+ } else { /* unknown */ -+ status = -EPROTO; -+ } -+ -+ fotg210_dbg(fotg210, -+ "dev%d ep%d%s qtd token %08x --> status %d\n", -+ usb_pipedevice(urb->pipe), -+ usb_pipeendpoint(urb->pipe), -+ usb_pipein(urb->pipe) ? "in" : "out", -+ token, status); -+ } -+ -+ return status; -+} -+ -+static void fotg210_urb_done(struct fotg210_hcd *fotg210, struct urb *urb, -+ int status) -+__releases(fotg210->lock) -+__acquires(fotg210->lock) -+{ -+ if (likely(urb->hcpriv != NULL)) { -+ struct fotg210_qh *qh = (struct fotg210_qh *) urb->hcpriv; -+ -+ /* S-mask in a QH means it's an interrupt urb */ -+ if ((qh->hw->hw_info2 & cpu_to_hc32(fotg210, QH_SMASK)) != 0) { -+ -+ /* ... update hc-wide periodic stats (for usbfs) */ -+ fotg210_to_hcd(fotg210)->self.bandwidth_int_reqs--; -+ } -+ } -+ -+ if (unlikely(urb->unlinked)) { -+ INCR(fotg210->stats.unlink); -+ } else { -+ /* report non-error and short read status as zero */ -+ if (status == -EINPROGRESS || status == -EREMOTEIO) -+ status = 0; -+ INCR(fotg210->stats.complete); -+ } -+ -+#ifdef FOTG210_URB_TRACE -+ fotg210_dbg(fotg210, -+ "%s %s urb %p ep%d%s status %d len %d/%d\n", -+ __func__, urb->dev->devpath, urb, -+ usb_pipeendpoint(urb->pipe), -+ usb_pipein(urb->pipe) ? "in" : "out", -+ status, -+ urb->actual_length, urb->transfer_buffer_length); -+#endif -+ -+ /* complete() can reenter this HCD */ -+ usb_hcd_unlink_urb_from_ep(fotg210_to_hcd(fotg210), urb); -+ spin_unlock(&fotg210->lock); -+ usb_hcd_giveback_urb(fotg210_to_hcd(fotg210), urb, status); -+ spin_lock(&fotg210->lock); -+} -+ -+static int qh_schedule(struct fotg210_hcd *fotg210, struct fotg210_qh *qh); -+ -+/* Process and free completed qtds for a qh, returning URBs to drivers. -+ * Chases up to qh->hw_current. Returns number of completions called, -+ * indicating how much "real" work we did. -+ */ -+static unsigned qh_completions(struct fotg210_hcd *fotg210, -+ struct fotg210_qh *qh) -+{ -+ struct fotg210_qtd *last, *end = qh->dummy; -+ struct fotg210_qtd *qtd, *tmp; -+ int last_status; -+ int stopped; -+ unsigned count = 0; -+ u8 state; -+ struct fotg210_qh_hw *hw = qh->hw; -+ -+ if (unlikely(list_empty(&qh->qtd_list))) -+ return count; -+ -+ /* completions (or tasks on other cpus) must never clobber HALT -+ * till we've gone through and cleaned everything up, even when -+ * they add urbs to this qh's queue or mark them for unlinking. -+ * -+ * NOTE: unlinking expects to be done in queue order. -+ * -+ * It's a bug for qh->qh_state to be anything other than -+ * QH_STATE_IDLE, unless our caller is scan_async() or -+ * scan_intr(). -+ */ -+ state = qh->qh_state; -+ qh->qh_state = QH_STATE_COMPLETING; -+ stopped = (state == QH_STATE_IDLE); -+ -+rescan: -+ last = NULL; -+ last_status = -EINPROGRESS; -+ qh->needs_rescan = 0; -+ -+ /* remove de-activated QTDs from front of queue. -+ * after faults (including short reads), cleanup this urb -+ * then let the queue advance. -+ * if queue is stopped, handles unlinks. -+ */ -+ list_for_each_entry_safe(qtd, tmp, &qh->qtd_list, qtd_list) { -+ struct urb *urb; -+ u32 token = 0; -+ -+ urb = qtd->urb; -+ -+ /* clean up any state from previous QTD ...*/ -+ if (last) { -+ if (likely(last->urb != urb)) { -+ fotg210_urb_done(fotg210, last->urb, -+ last_status); -+ count++; -+ last_status = -EINPROGRESS; -+ } -+ fotg210_qtd_free(fotg210, last); -+ last = NULL; -+ } -+ -+ /* ignore urbs submitted during completions we reported */ -+ if (qtd == end) -+ break; -+ -+ /* hardware copies qtd out of qh overlay */ -+ rmb(); -+ token = hc32_to_cpu(fotg210, qtd->hw_token); -+ -+ /* always clean up qtds the hc de-activated */ -+retry_xacterr: -+ if ((token & QTD_STS_ACTIVE) == 0) { -+ -+ /* Report Data Buffer Error: non-fatal but useful */ -+ if (token & QTD_STS_DBE) -+ fotg210_dbg(fotg210, -+ "detected DataBufferErr for urb %p ep%d%s len %d, qtd %p [qh %p]\n", -+ urb, usb_endpoint_num(&urb->ep->desc), -+ usb_endpoint_dir_in(&urb->ep->desc) -+ ? "in" : "out", -+ urb->transfer_buffer_length, qtd, qh); -+ -+ /* on STALL, error, and short reads this urb must -+ * complete and all its qtds must be recycled. -+ */ -+ if ((token & QTD_STS_HALT) != 0) { -+ -+ /* retry transaction errors until we -+ * reach the software xacterr limit -+ */ -+ if ((token & QTD_STS_XACT) && -+ QTD_CERR(token) == 0 && -+ ++qh->xacterrs < QH_XACTERR_MAX && -+ !urb->unlinked) { -+ fotg210_dbg(fotg210, -+ "detected XactErr len %zu/%zu retry %d\n", -+ qtd->length - QTD_LENGTH(token), -+ qtd->length, -+ qh->xacterrs); -+ -+ /* reset the token in the qtd and the -+ * qh overlay (which still contains -+ * the qtd) so that we pick up from -+ * where we left off -+ */ -+ token &= ~QTD_STS_HALT; -+ token |= QTD_STS_ACTIVE | -+ (FOTG210_TUNE_CERR << 10); -+ qtd->hw_token = cpu_to_hc32(fotg210, -+ token); -+ wmb(); -+ hw->hw_token = cpu_to_hc32(fotg210, -+ token); -+ goto retry_xacterr; -+ } -+ stopped = 1; -+ -+ /* magic dummy for some short reads; qh won't advance. -+ * that silicon quirk can kick in with this dummy too. -+ * -+ * other short reads won't stop the queue, including -+ * control transfers (status stage handles that) or -+ * most other single-qtd reads ... the queue stops if -+ * URB_SHORT_NOT_OK was set so the driver submitting -+ * the urbs could clean it up. -+ */ -+ } else if (IS_SHORT_READ(token) && -+ !(qtd->hw_alt_next & -+ FOTG210_LIST_END(fotg210))) { -+ stopped = 1; -+ } -+ -+ /* stop scanning when we reach qtds the hc is using */ -+ } else if (likely(!stopped -+ && fotg210->rh_state >= FOTG210_RH_RUNNING)) { -+ break; -+ -+ /* scan the whole queue for unlinks whenever it stops */ -+ } else { -+ stopped = 1; -+ -+ /* cancel everything if we halt, suspend, etc */ -+ if (fotg210->rh_state < FOTG210_RH_RUNNING) -+ last_status = -ESHUTDOWN; -+ -+ /* this qtd is active; skip it unless a previous qtd -+ * for its urb faulted, or its urb was canceled. -+ */ -+ else if (last_status == -EINPROGRESS && !urb->unlinked) -+ continue; -+ -+ /* qh unlinked; token in overlay may be most current */ -+ if (state == QH_STATE_IDLE && -+ cpu_to_hc32(fotg210, qtd->qtd_dma) -+ == hw->hw_current) { -+ token = hc32_to_cpu(fotg210, hw->hw_token); -+ -+ /* An unlink may leave an incomplete -+ * async transaction in the TT buffer. -+ * We have to clear it. -+ */ -+ fotg210_clear_tt_buffer(fotg210, qh, urb, -+ token); -+ } -+ } -+ -+ /* unless we already know the urb's status, collect qtd status -+ * and update count of bytes transferred. in common short read -+ * cases with only one data qtd (including control transfers), -+ * queue processing won't halt. but with two or more qtds (for -+ * example, with a 32 KB transfer), when the first qtd gets a -+ * short read the second must be removed by hand. -+ */ -+ if (last_status == -EINPROGRESS) { -+ last_status = qtd_copy_status(fotg210, urb, -+ qtd->length, token); -+ if (last_status == -EREMOTEIO && -+ (qtd->hw_alt_next & -+ FOTG210_LIST_END(fotg210))) -+ last_status = -EINPROGRESS; -+ -+ /* As part of low/full-speed endpoint-halt processing -+ * we must clear the TT buffer (11.17.5). -+ */ -+ if (unlikely(last_status != -EINPROGRESS && -+ last_status != -EREMOTEIO)) { -+ /* The TT's in some hubs malfunction when they -+ * receive this request following a STALL (they -+ * stop sending isochronous packets). Since a -+ * STALL can't leave the TT buffer in a busy -+ * state (if you believe Figures 11-48 - 11-51 -+ * in the USB 2.0 spec), we won't clear the TT -+ * buffer in this case. Strictly speaking this -+ * is a violation of the spec. -+ */ -+ if (last_status != -EPIPE) -+ fotg210_clear_tt_buffer(fotg210, qh, -+ urb, token); -+ } -+ } -+ -+ /* if we're removing something not at the queue head, -+ * patch the hardware queue pointer. -+ */ -+ if (stopped && qtd->qtd_list.prev != &qh->qtd_list) { -+ last = list_entry(qtd->qtd_list.prev, -+ struct fotg210_qtd, qtd_list); -+ last->hw_next = qtd->hw_next; -+ } -+ -+ /* remove qtd; it's recycled after possible urb completion */ -+ list_del(&qtd->qtd_list); -+ last = qtd; -+ -+ /* reinit the xacterr counter for the next qtd */ -+ qh->xacterrs = 0; -+ } -+ -+ /* last urb's completion might still need calling */ -+ if (likely(last != NULL)) { -+ fotg210_urb_done(fotg210, last->urb, last_status); -+ count++; -+ fotg210_qtd_free(fotg210, last); -+ } -+ -+ /* Do we need to rescan for URBs dequeued during a giveback? */ -+ if (unlikely(qh->needs_rescan)) { -+ /* If the QH is already unlinked, do the rescan now. */ -+ if (state == QH_STATE_IDLE) -+ goto rescan; -+ -+ /* Otherwise we have to wait until the QH is fully unlinked. -+ * Our caller will start an unlink if qh->needs_rescan is -+ * set. But if an unlink has already started, nothing needs -+ * to be done. -+ */ -+ if (state != QH_STATE_LINKED) -+ qh->needs_rescan = 0; -+ } -+ -+ /* restore original state; caller must unlink or relink */ -+ qh->qh_state = state; -+ -+ /* be sure the hardware's done with the qh before refreshing -+ * it after fault cleanup, or recovering from silicon wrongly -+ * overlaying the dummy qtd (which reduces DMA chatter). -+ */ -+ if (stopped != 0 || hw->hw_qtd_next == FOTG210_LIST_END(fotg210)) { -+ switch (state) { -+ case QH_STATE_IDLE: -+ qh_refresh(fotg210, qh); -+ break; -+ case QH_STATE_LINKED: -+ /* We won't refresh a QH that's linked (after the HC -+ * stopped the queue). That avoids a race: -+ * - HC reads first part of QH; -+ * - CPU updates that first part and the token; -+ * - HC reads rest of that QH, including token -+ * Result: HC gets an inconsistent image, and then -+ * DMAs to/from the wrong memory (corrupting it). -+ * -+ * That should be rare for interrupt transfers, -+ * except maybe high bandwidth ... -+ */ -+ -+ /* Tell the caller to start an unlink */ -+ qh->needs_rescan = 1; -+ break; -+ /* otherwise, unlink already started */ -+ } -+ } -+ -+ return count; -+} -+ -+/* reverse of qh_urb_transaction: free a list of TDs. -+ * used for cleanup after errors, before HC sees an URB's TDs. -+ */ -+static void qtd_list_free(struct fotg210_hcd *fotg210, struct urb *urb, -+ struct list_head *head) -+{ -+ struct fotg210_qtd *qtd, *temp; -+ -+ list_for_each_entry_safe(qtd, temp, head, qtd_list) { -+ list_del(&qtd->qtd_list); -+ fotg210_qtd_free(fotg210, qtd); -+ } -+} -+ -+/* create a list of filled qtds for this URB; won't link into qh. -+ */ -+static struct list_head *qh_urb_transaction(struct fotg210_hcd *fotg210, -+ struct urb *urb, struct list_head *head, gfp_t flags) -+{ -+ struct fotg210_qtd *qtd, *qtd_prev; -+ dma_addr_t buf; -+ int len, this_sg_len, maxpacket; -+ int is_input; -+ u32 token; -+ int i; -+ struct scatterlist *sg; -+ -+ /* -+ * URBs map to sequences of QTDs: one logical transaction -+ */ -+ qtd = fotg210_qtd_alloc(fotg210, flags); -+ if (unlikely(!qtd)) -+ return NULL; -+ list_add_tail(&qtd->qtd_list, head); -+ qtd->urb = urb; -+ -+ token = QTD_STS_ACTIVE; -+ token |= (FOTG210_TUNE_CERR << 10); -+ /* for split transactions, SplitXState initialized to zero */ -+ -+ len = urb->transfer_buffer_length; -+ is_input = usb_pipein(urb->pipe); -+ if (usb_pipecontrol(urb->pipe)) { -+ /* SETUP pid */ -+ qtd_fill(fotg210, qtd, urb->setup_dma, -+ sizeof(struct usb_ctrlrequest), -+ token | (2 /* "setup" */ << 8), 8); -+ -+ /* ... and always at least one more pid */ -+ token ^= QTD_TOGGLE; -+ qtd_prev = qtd; -+ qtd = fotg210_qtd_alloc(fotg210, flags); -+ if (unlikely(!qtd)) -+ goto cleanup; -+ qtd->urb = urb; -+ qtd_prev->hw_next = QTD_NEXT(fotg210, qtd->qtd_dma); -+ list_add_tail(&qtd->qtd_list, head); -+ -+ /* for zero length DATA stages, STATUS is always IN */ -+ if (len == 0) -+ token |= (1 /* "in" */ << 8); -+ } -+ -+ /* -+ * data transfer stage: buffer setup -+ */ -+ i = urb->num_mapped_sgs; -+ if (len > 0 && i > 0) { -+ sg = urb->sg; -+ buf = sg_dma_address(sg); -+ -+ /* urb->transfer_buffer_length may be smaller than the -+ * size of the scatterlist (or vice versa) -+ */ -+ this_sg_len = min_t(int, sg_dma_len(sg), len); -+ } else { -+ sg = NULL; -+ buf = urb->transfer_dma; -+ this_sg_len = len; -+ } -+ -+ if (is_input) -+ token |= (1 /* "in" */ << 8); -+ /* else it's already initted to "out" pid (0 << 8) */ -+ -+ maxpacket = usb_maxpacket(urb->dev, urb->pipe); -+ -+ /* -+ * buffer gets wrapped in one or more qtds; -+ * last one may be "short" (including zero len) -+ * and may serve as a control status ack -+ */ -+ for (;;) { -+ int this_qtd_len; -+ -+ this_qtd_len = qtd_fill(fotg210, qtd, buf, this_sg_len, token, -+ maxpacket); -+ this_sg_len -= this_qtd_len; -+ len -= this_qtd_len; -+ buf += this_qtd_len; -+ -+ /* -+ * short reads advance to a "magic" dummy instead of the next -+ * qtd ... that forces the queue to stop, for manual cleanup. -+ * (this will usually be overridden later.) -+ */ -+ if (is_input) -+ qtd->hw_alt_next = fotg210->async->hw->hw_alt_next; -+ -+ /* qh makes control packets use qtd toggle; maybe switch it */ -+ if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0) -+ token ^= QTD_TOGGLE; -+ -+ if (likely(this_sg_len <= 0)) { -+ if (--i <= 0 || len <= 0) -+ break; -+ sg = sg_next(sg); -+ buf = sg_dma_address(sg); -+ this_sg_len = min_t(int, sg_dma_len(sg), len); -+ } -+ -+ qtd_prev = qtd; -+ qtd = fotg210_qtd_alloc(fotg210, flags); -+ if (unlikely(!qtd)) -+ goto cleanup; -+ qtd->urb = urb; -+ qtd_prev->hw_next = QTD_NEXT(fotg210, qtd->qtd_dma); -+ list_add_tail(&qtd->qtd_list, head); -+ } -+ -+ /* -+ * unless the caller requires manual cleanup after short reads, -+ * have the alt_next mechanism keep the queue running after the -+ * last data qtd (the only one, for control and most other cases). -+ */ -+ if (likely((urb->transfer_flags & URB_SHORT_NOT_OK) == 0 || -+ usb_pipecontrol(urb->pipe))) -+ qtd->hw_alt_next = FOTG210_LIST_END(fotg210); -+ -+ /* -+ * control requests may need a terminating data "status" ack; -+ * other OUT ones may need a terminating short packet -+ * (zero length). -+ */ -+ if (likely(urb->transfer_buffer_length != 0)) { -+ int one_more = 0; -+ -+ if (usb_pipecontrol(urb->pipe)) { -+ one_more = 1; -+ token ^= 0x0100; /* "in" <--> "out" */ -+ token |= QTD_TOGGLE; /* force DATA1 */ -+ } else if (usb_pipeout(urb->pipe) -+ && (urb->transfer_flags & URB_ZERO_PACKET) -+ && !(urb->transfer_buffer_length % maxpacket)) { -+ one_more = 1; -+ } -+ if (one_more) { -+ qtd_prev = qtd; -+ qtd = fotg210_qtd_alloc(fotg210, flags); -+ if (unlikely(!qtd)) -+ goto cleanup; -+ qtd->urb = urb; -+ qtd_prev->hw_next = QTD_NEXT(fotg210, qtd->qtd_dma); -+ list_add_tail(&qtd->qtd_list, head); -+ -+ /* never any data in such packets */ -+ qtd_fill(fotg210, qtd, 0, 0, token, 0); -+ } -+ } -+ -+ /* by default, enable interrupt on urb completion */ -+ if (likely(!(urb->transfer_flags & URB_NO_INTERRUPT))) -+ qtd->hw_token |= cpu_to_hc32(fotg210, QTD_IOC); -+ return head; -+ -+cleanup: -+ qtd_list_free(fotg210, urb, head); -+ return NULL; -+} -+ -+/* Would be best to create all qh's from config descriptors, -+ * when each interface/altsetting is established. Unlink -+ * any previous qh and cancel its urbs first; endpoints are -+ * implicitly reset then (data toggle too). -+ * That'd mean updating how usbcore talks to HCDs. (2.7?) -+ */ -+ -+ -+/* Each QH holds a qtd list; a QH is used for everything except iso. -+ * -+ * For interrupt urbs, the scheduler must set the microframe scheduling -+ * mask(s) each time the QH gets scheduled. For highspeed, that's -+ * just one microframe in the s-mask. For split interrupt transactions -+ * there are additional complications: c-mask, maybe FSTNs. -+ */ -+static struct fotg210_qh *qh_make(struct fotg210_hcd *fotg210, struct urb *urb, -+ gfp_t flags) -+{ -+ struct fotg210_qh *qh = fotg210_qh_alloc(fotg210, flags); -+ struct usb_host_endpoint *ep; -+ u32 info1 = 0, info2 = 0; -+ int is_input, type; -+ int maxp = 0; -+ int mult; -+ struct usb_tt *tt = urb->dev->tt; -+ struct fotg210_qh_hw *hw; -+ -+ if (!qh) -+ return qh; -+ -+ /* -+ * init endpoint/device data for this QH -+ */ -+ info1 |= usb_pipeendpoint(urb->pipe) << 8; -+ info1 |= usb_pipedevice(urb->pipe) << 0; -+ -+ is_input = usb_pipein(urb->pipe); -+ type = usb_pipetype(urb->pipe); -+ ep = usb_pipe_endpoint(urb->dev, urb->pipe); -+ maxp = usb_endpoint_maxp(&ep->desc); -+ mult = usb_endpoint_maxp_mult(&ep->desc); -+ -+ /* 1024 byte maxpacket is a hardware ceiling. High bandwidth -+ * acts like up to 3KB, but is built from smaller packets. -+ */ -+ if (maxp > 1024) { -+ fotg210_dbg(fotg210, "bogus qh maxpacket %d\n", maxp); -+ goto done; -+ } -+ -+ /* Compute interrupt scheduling parameters just once, and save. -+ * - allowing for high bandwidth, how many nsec/uframe are used? -+ * - split transactions need a second CSPLIT uframe; same question -+ * - splits also need a schedule gap (for full/low speed I/O) -+ * - qh has a polling interval -+ * -+ * For control/bulk requests, the HC or TT handles these. -+ */ -+ if (type == PIPE_INTERRUPT) { -+ qh->usecs = NS_TO_US(usb_calc_bus_time(USB_SPEED_HIGH, -+ is_input, 0, mult * maxp)); -+ qh->start = NO_FRAME; -+ -+ if (urb->dev->speed == USB_SPEED_HIGH) { -+ qh->c_usecs = 0; -+ qh->gap_uf = 0; -+ -+ qh->period = urb->interval >> 3; -+ if (qh->period == 0 && urb->interval != 1) { -+ /* NOTE interval 2 or 4 uframes could work. -+ * But interval 1 scheduling is simpler, and -+ * includes high bandwidth. -+ */ -+ urb->interval = 1; -+ } else if (qh->period > fotg210->periodic_size) { -+ qh->period = fotg210->periodic_size; -+ urb->interval = qh->period << 3; -+ } -+ } else { -+ int think_time; -+ -+ /* gap is f(FS/LS transfer times) */ -+ qh->gap_uf = 1 + usb_calc_bus_time(urb->dev->speed, -+ is_input, 0, maxp) / (125 * 1000); -+ -+ /* FIXME this just approximates SPLIT/CSPLIT times */ -+ if (is_input) { /* SPLIT, gap, CSPLIT+DATA */ -+ qh->c_usecs = qh->usecs + HS_USECS(0); -+ qh->usecs = HS_USECS(1); -+ } else { /* SPLIT+DATA, gap, CSPLIT */ -+ qh->usecs += HS_USECS(1); -+ qh->c_usecs = HS_USECS(0); -+ } -+ -+ think_time = tt ? tt->think_time : 0; -+ qh->tt_usecs = NS_TO_US(think_time + -+ usb_calc_bus_time(urb->dev->speed, -+ is_input, 0, maxp)); -+ qh->period = urb->interval; -+ if (qh->period > fotg210->periodic_size) { -+ qh->period = fotg210->periodic_size; -+ urb->interval = qh->period; -+ } -+ } -+ } -+ -+ /* support for tt scheduling, and access to toggles */ -+ qh->dev = urb->dev; -+ -+ /* using TT? */ -+ switch (urb->dev->speed) { -+ case USB_SPEED_LOW: -+ info1 |= QH_LOW_SPEED; -+ fallthrough; -+ -+ case USB_SPEED_FULL: -+ /* EPS 0 means "full" */ -+ if (type != PIPE_INTERRUPT) -+ info1 |= (FOTG210_TUNE_RL_TT << 28); -+ if (type == PIPE_CONTROL) { -+ info1 |= QH_CONTROL_EP; /* for TT */ -+ info1 |= QH_TOGGLE_CTL; /* toggle from qtd */ -+ } -+ info1 |= maxp << 16; -+ -+ info2 |= (FOTG210_TUNE_MULT_TT << 30); -+ -+ /* Some Freescale processors have an erratum in which the -+ * port number in the queue head was 0..N-1 instead of 1..N. -+ */ -+ if (fotg210_has_fsl_portno_bug(fotg210)) -+ info2 |= (urb->dev->ttport-1) << 23; -+ else -+ info2 |= urb->dev->ttport << 23; -+ -+ /* set the address of the TT; for TDI's integrated -+ * root hub tt, leave it zeroed. -+ */ -+ if (tt && tt->hub != fotg210_to_hcd(fotg210)->self.root_hub) -+ info2 |= tt->hub->devnum << 16; -+ -+ /* NOTE: if (PIPE_INTERRUPT) { scheduler sets c-mask } */ -+ -+ break; -+ -+ case USB_SPEED_HIGH: /* no TT involved */ -+ info1 |= QH_HIGH_SPEED; -+ if (type == PIPE_CONTROL) { -+ info1 |= (FOTG210_TUNE_RL_HS << 28); -+ info1 |= 64 << 16; /* usb2 fixed maxpacket */ -+ info1 |= QH_TOGGLE_CTL; /* toggle from qtd */ -+ info2 |= (FOTG210_TUNE_MULT_HS << 30); -+ } else if (type == PIPE_BULK) { -+ info1 |= (FOTG210_TUNE_RL_HS << 28); -+ /* The USB spec says that high speed bulk endpoints -+ * always use 512 byte maxpacket. But some device -+ * vendors decided to ignore that, and MSFT is happy -+ * to help them do so. So now people expect to use -+ * such nonconformant devices with Linux too; sigh. -+ */ -+ info1 |= maxp << 16; -+ info2 |= (FOTG210_TUNE_MULT_HS << 30); -+ } else { /* PIPE_INTERRUPT */ -+ info1 |= maxp << 16; -+ info2 |= mult << 30; -+ } -+ break; -+ default: -+ fotg210_dbg(fotg210, "bogus dev %p speed %d\n", urb->dev, -+ urb->dev->speed); -+done: -+ qh_destroy(fotg210, qh); -+ return NULL; -+ } -+ -+ /* NOTE: if (PIPE_INTERRUPT) { scheduler sets s-mask } */ -+ -+ /* init as live, toggle clear, advance to dummy */ -+ qh->qh_state = QH_STATE_IDLE; -+ hw = qh->hw; -+ hw->hw_info1 = cpu_to_hc32(fotg210, info1); -+ hw->hw_info2 = cpu_to_hc32(fotg210, info2); -+ qh->is_out = !is_input; -+ usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), !is_input, 1); -+ qh_refresh(fotg210, qh); -+ return qh; -+} -+ -+static void enable_async(struct fotg210_hcd *fotg210) -+{ -+ if (fotg210->async_count++) -+ return; -+ -+ /* Stop waiting to turn off the async schedule */ -+ fotg210->enabled_hrtimer_events &= ~BIT(FOTG210_HRTIMER_DISABLE_ASYNC); -+ -+ /* Don't start the schedule until ASS is 0 */ -+ fotg210_poll_ASS(fotg210); -+ turn_on_io_watchdog(fotg210); -+} -+ -+static void disable_async(struct fotg210_hcd *fotg210) -+{ -+ if (--fotg210->async_count) -+ return; -+ -+ /* The async schedule and async_unlink list are supposed to be empty */ -+ WARN_ON(fotg210->async->qh_next.qh || fotg210->async_unlink); -+ -+ /* Don't turn off the schedule until ASS is 1 */ -+ fotg210_poll_ASS(fotg210); -+} -+ -+/* move qh (and its qtds) onto async queue; maybe enable queue. */ -+ -+static void qh_link_async(struct fotg210_hcd *fotg210, struct fotg210_qh *qh) -+{ -+ __hc32 dma = QH_NEXT(fotg210, qh->qh_dma); -+ struct fotg210_qh *head; -+ -+ /* Don't link a QH if there's a Clear-TT-Buffer pending */ -+ if (unlikely(qh->clearing_tt)) -+ return; -+ -+ WARN_ON(qh->qh_state != QH_STATE_IDLE); -+ -+ /* clear halt and/or toggle; and maybe recover from silicon quirk */ -+ qh_refresh(fotg210, qh); -+ -+ /* splice right after start */ -+ head = fotg210->async; -+ qh->qh_next = head->qh_next; -+ qh->hw->hw_next = head->hw->hw_next; -+ wmb(); -+ -+ head->qh_next.qh = qh; -+ head->hw->hw_next = dma; -+ -+ qh->xacterrs = 0; -+ qh->qh_state = QH_STATE_LINKED; -+ /* qtd completions reported later by interrupt */ -+ -+ enable_async(fotg210); -+} -+ -+/* For control/bulk/interrupt, return QH with these TDs appended. -+ * Allocates and initializes the QH if necessary. -+ * Returns null if it can't allocate a QH it needs to. -+ * If the QH has TDs (urbs) already, that's great. -+ */ -+static struct fotg210_qh *qh_append_tds(struct fotg210_hcd *fotg210, -+ struct urb *urb, struct list_head *qtd_list, -+ int epnum, void **ptr) -+{ -+ struct fotg210_qh *qh = NULL; -+ __hc32 qh_addr_mask = cpu_to_hc32(fotg210, 0x7f); -+ -+ qh = (struct fotg210_qh *) *ptr; -+ if (unlikely(qh == NULL)) { -+ /* can't sleep here, we have fotg210->lock... */ -+ qh = qh_make(fotg210, urb, GFP_ATOMIC); -+ *ptr = qh; -+ } -+ if (likely(qh != NULL)) { -+ struct fotg210_qtd *qtd; -+ -+ if (unlikely(list_empty(qtd_list))) -+ qtd = NULL; -+ else -+ qtd = list_entry(qtd_list->next, struct fotg210_qtd, -+ qtd_list); -+ -+ /* control qh may need patching ... */ -+ if (unlikely(epnum == 0)) { -+ /* usb_reset_device() briefly reverts to address 0 */ -+ if (usb_pipedevice(urb->pipe) == 0) -+ qh->hw->hw_info1 &= ~qh_addr_mask; -+ } -+ -+ /* just one way to queue requests: swap with the dummy qtd. -+ * only hc or qh_refresh() ever modify the overlay. -+ */ -+ if (likely(qtd != NULL)) { -+ struct fotg210_qtd *dummy; -+ dma_addr_t dma; -+ __hc32 token; -+ -+ /* to avoid racing the HC, use the dummy td instead of -+ * the first td of our list (becomes new dummy). both -+ * tds stay deactivated until we're done, when the -+ * HC is allowed to fetch the old dummy (4.10.2). -+ */ -+ token = qtd->hw_token; -+ qtd->hw_token = HALT_BIT(fotg210); -+ -+ dummy = qh->dummy; -+ -+ dma = dummy->qtd_dma; -+ *dummy = *qtd; -+ dummy->qtd_dma = dma; -+ -+ list_del(&qtd->qtd_list); -+ list_add(&dummy->qtd_list, qtd_list); -+ list_splice_tail(qtd_list, &qh->qtd_list); -+ -+ fotg210_qtd_init(fotg210, qtd, qtd->qtd_dma); -+ qh->dummy = qtd; -+ -+ /* hc must see the new dummy at list end */ -+ dma = qtd->qtd_dma; -+ qtd = list_entry(qh->qtd_list.prev, -+ struct fotg210_qtd, qtd_list); -+ qtd->hw_next = QTD_NEXT(fotg210, dma); -+ -+ /* let the hc process these next qtds */ -+ wmb(); -+ dummy->hw_token = token; -+ -+ urb->hcpriv = qh; -+ } -+ } -+ return qh; -+} -+ -+static int submit_async(struct fotg210_hcd *fotg210, struct urb *urb, -+ struct list_head *qtd_list, gfp_t mem_flags) -+{ -+ int epnum; -+ unsigned long flags; -+ struct fotg210_qh *qh = NULL; -+ int rc; -+ -+ epnum = urb->ep->desc.bEndpointAddress; -+ -+#ifdef FOTG210_URB_TRACE -+ { -+ struct fotg210_qtd *qtd; -+ -+ qtd = list_entry(qtd_list->next, struct fotg210_qtd, qtd_list); -+ fotg210_dbg(fotg210, -+ "%s %s urb %p ep%d%s len %d, qtd %p [qh %p]\n", -+ __func__, urb->dev->devpath, urb, -+ epnum & 0x0f, (epnum & USB_DIR_IN) -+ ? "in" : "out", -+ urb->transfer_buffer_length, -+ qtd, urb->ep->hcpriv); -+ } -+#endif -+ -+ spin_lock_irqsave(&fotg210->lock, flags); -+ if (unlikely(!HCD_HW_ACCESSIBLE(fotg210_to_hcd(fotg210)))) { -+ rc = -ESHUTDOWN; -+ goto done; -+ } -+ rc = usb_hcd_link_urb_to_ep(fotg210_to_hcd(fotg210), urb); -+ if (unlikely(rc)) -+ goto done; -+ -+ qh = qh_append_tds(fotg210, urb, qtd_list, epnum, &urb->ep->hcpriv); -+ if (unlikely(qh == NULL)) { -+ usb_hcd_unlink_urb_from_ep(fotg210_to_hcd(fotg210), urb); -+ rc = -ENOMEM; -+ goto done; -+ } -+ -+ /* Control/bulk operations through TTs don't need scheduling, -+ * the HC and TT handle it when the TT has a buffer ready. -+ */ -+ if (likely(qh->qh_state == QH_STATE_IDLE)) -+ qh_link_async(fotg210, qh); -+done: -+ spin_unlock_irqrestore(&fotg210->lock, flags); -+ if (unlikely(qh == NULL)) -+ qtd_list_free(fotg210, urb, qtd_list); -+ return rc; -+} -+ -+static void single_unlink_async(struct fotg210_hcd *fotg210, -+ struct fotg210_qh *qh) -+{ -+ struct fotg210_qh *prev; -+ -+ /* Add to the end of the list of QHs waiting for the next IAAD */ -+ qh->qh_state = QH_STATE_UNLINK; -+ if (fotg210->async_unlink) -+ fotg210->async_unlink_last->unlink_next = qh; -+ else -+ fotg210->async_unlink = qh; -+ fotg210->async_unlink_last = qh; -+ -+ /* Unlink it from the schedule */ -+ prev = fotg210->async; -+ while (prev->qh_next.qh != qh) -+ prev = prev->qh_next.qh; -+ -+ prev->hw->hw_next = qh->hw->hw_next; -+ prev->qh_next = qh->qh_next; -+ if (fotg210->qh_scan_next == qh) -+ fotg210->qh_scan_next = qh->qh_next.qh; -+} -+ -+static void start_iaa_cycle(struct fotg210_hcd *fotg210, bool nested) -+{ -+ /* -+ * Do nothing if an IAA cycle is already running or -+ * if one will be started shortly. -+ */ -+ if (fotg210->async_iaa || fotg210->async_unlinking) -+ return; -+ -+ /* Do all the waiting QHs at once */ -+ fotg210->async_iaa = fotg210->async_unlink; -+ fotg210->async_unlink = NULL; -+ -+ /* If the controller isn't running, we don't have to wait for it */ -+ if (unlikely(fotg210->rh_state < FOTG210_RH_RUNNING)) { -+ if (!nested) /* Avoid recursion */ -+ end_unlink_async(fotg210); -+ -+ /* Otherwise start a new IAA cycle */ -+ } else if (likely(fotg210->rh_state == FOTG210_RH_RUNNING)) { -+ /* Make sure the unlinks are all visible to the hardware */ -+ wmb(); -+ -+ fotg210_writel(fotg210, fotg210->command | CMD_IAAD, -+ &fotg210->regs->command); -+ fotg210_readl(fotg210, &fotg210->regs->command); -+ fotg210_enable_event(fotg210, FOTG210_HRTIMER_IAA_WATCHDOG, -+ true); -+ } -+} -+ -+/* the async qh for the qtds being unlinked are now gone from the HC */ -+ -+static void end_unlink_async(struct fotg210_hcd *fotg210) -+{ -+ struct fotg210_qh *qh; -+ -+ /* Process the idle QHs */ -+restart: -+ fotg210->async_unlinking = true; -+ while (fotg210->async_iaa) { -+ qh = fotg210->async_iaa; -+ fotg210->async_iaa = qh->unlink_next; -+ qh->unlink_next = NULL; -+ -+ qh->qh_state = QH_STATE_IDLE; -+ qh->qh_next.qh = NULL; -+ -+ qh_completions(fotg210, qh); -+ if (!list_empty(&qh->qtd_list) && -+ fotg210->rh_state == FOTG210_RH_RUNNING) -+ qh_link_async(fotg210, qh); -+ disable_async(fotg210); -+ } -+ fotg210->async_unlinking = false; -+ -+ /* Start a new IAA cycle if any QHs are waiting for it */ -+ if (fotg210->async_unlink) { -+ start_iaa_cycle(fotg210, true); -+ if (unlikely(fotg210->rh_state < FOTG210_RH_RUNNING)) -+ goto restart; -+ } -+} -+ -+static void unlink_empty_async(struct fotg210_hcd *fotg210) -+{ -+ struct fotg210_qh *qh, *next; -+ bool stopped = (fotg210->rh_state < FOTG210_RH_RUNNING); -+ bool check_unlinks_later = false; -+ -+ /* Unlink all the async QHs that have been empty for a timer cycle */ -+ next = fotg210->async->qh_next.qh; -+ while (next) { -+ qh = next; -+ next = qh->qh_next.qh; -+ -+ if (list_empty(&qh->qtd_list) && -+ qh->qh_state == QH_STATE_LINKED) { -+ if (!stopped && qh->unlink_cycle == -+ fotg210->async_unlink_cycle) -+ check_unlinks_later = true; -+ else -+ single_unlink_async(fotg210, qh); -+ } -+ } -+ -+ /* Start a new IAA cycle if any QHs are waiting for it */ -+ if (fotg210->async_unlink) -+ start_iaa_cycle(fotg210, false); -+ -+ /* QHs that haven't been empty for long enough will be handled later */ -+ if (check_unlinks_later) { -+ fotg210_enable_event(fotg210, FOTG210_HRTIMER_ASYNC_UNLINKS, -+ true); -+ ++fotg210->async_unlink_cycle; -+ } -+} -+ -+/* makes sure the async qh will become idle */ -+/* caller must own fotg210->lock */ -+ -+static void start_unlink_async(struct fotg210_hcd *fotg210, -+ struct fotg210_qh *qh) -+{ -+ /* -+ * If the QH isn't linked then there's nothing we can do -+ * unless we were called during a giveback, in which case -+ * qh_completions() has to deal with it. -+ */ -+ if (qh->qh_state != QH_STATE_LINKED) { -+ if (qh->qh_state == QH_STATE_COMPLETING) -+ qh->needs_rescan = 1; -+ return; -+ } -+ -+ single_unlink_async(fotg210, qh); -+ start_iaa_cycle(fotg210, false); -+} -+ -+static void scan_async(struct fotg210_hcd *fotg210) -+{ -+ struct fotg210_qh *qh; -+ bool check_unlinks_later = false; -+ -+ fotg210->qh_scan_next = fotg210->async->qh_next.qh; -+ while (fotg210->qh_scan_next) { -+ qh = fotg210->qh_scan_next; -+ fotg210->qh_scan_next = qh->qh_next.qh; -+rescan: -+ /* clean any finished work for this qh */ -+ if (!list_empty(&qh->qtd_list)) { -+ int temp; -+ -+ /* -+ * Unlinks could happen here; completion reporting -+ * drops the lock. That's why fotg210->qh_scan_next -+ * always holds the next qh to scan; if the next qh -+ * gets unlinked then fotg210->qh_scan_next is adjusted -+ * in single_unlink_async(). -+ */ -+ temp = qh_completions(fotg210, qh); -+ if (qh->needs_rescan) { -+ start_unlink_async(fotg210, qh); -+ } else if (list_empty(&qh->qtd_list) -+ && qh->qh_state == QH_STATE_LINKED) { -+ qh->unlink_cycle = fotg210->async_unlink_cycle; -+ check_unlinks_later = true; -+ } else if (temp != 0) -+ goto rescan; -+ } -+ } -+ -+ /* -+ * Unlink empty entries, reducing DMA usage as well -+ * as HCD schedule-scanning costs. Delay for any qh -+ * we just scanned, there's a not-unusual case that it -+ * doesn't stay idle for long. -+ */ -+ if (check_unlinks_later && fotg210->rh_state == FOTG210_RH_RUNNING && -+ !(fotg210->enabled_hrtimer_events & -+ BIT(FOTG210_HRTIMER_ASYNC_UNLINKS))) { -+ fotg210_enable_event(fotg210, -+ FOTG210_HRTIMER_ASYNC_UNLINKS, true); -+ ++fotg210->async_unlink_cycle; -+ } -+} -+/* EHCI scheduled transaction support: interrupt, iso, split iso -+ * These are called "periodic" transactions in the EHCI spec. -+ * -+ * Note that for interrupt transfers, the QH/QTD manipulation is shared -+ * with the "asynchronous" transaction support (control/bulk transfers). -+ * The only real difference is in how interrupt transfers are scheduled. -+ * -+ * For ISO, we make an "iso_stream" head to serve the same role as a QH. -+ * It keeps track of every ITD (or SITD) that's linked, and holds enough -+ * pre-calculated schedule data to make appending to the queue be quick. -+ */ -+static int fotg210_get_frame(struct usb_hcd *hcd); -+ -+/* periodic_next_shadow - return "next" pointer on shadow list -+ * @periodic: host pointer to qh/itd -+ * @tag: hardware tag for type of this record -+ */ -+static union fotg210_shadow *periodic_next_shadow(struct fotg210_hcd *fotg210, -+ union fotg210_shadow *periodic, __hc32 tag) -+{ -+ switch (hc32_to_cpu(fotg210, tag)) { -+ case Q_TYPE_QH: -+ return &periodic->qh->qh_next; -+ case Q_TYPE_FSTN: -+ return &periodic->fstn->fstn_next; -+ default: -+ return &periodic->itd->itd_next; -+ } -+} -+ -+static __hc32 *shadow_next_periodic(struct fotg210_hcd *fotg210, -+ union fotg210_shadow *periodic, __hc32 tag) -+{ -+ switch (hc32_to_cpu(fotg210, tag)) { -+ /* our fotg210_shadow.qh is actually software part */ -+ case Q_TYPE_QH: -+ return &periodic->qh->hw->hw_next; -+ /* others are hw parts */ -+ default: -+ return periodic->hw_next; -+ } -+} -+ -+/* caller must hold fotg210->lock */ -+static void periodic_unlink(struct fotg210_hcd *fotg210, unsigned frame, -+ void *ptr) -+{ -+ union fotg210_shadow *prev_p = &fotg210->pshadow[frame]; -+ __hc32 *hw_p = &fotg210->periodic[frame]; -+ union fotg210_shadow here = *prev_p; -+ -+ /* find predecessor of "ptr"; hw and shadow lists are in sync */ -+ while (here.ptr && here.ptr != ptr) { -+ prev_p = periodic_next_shadow(fotg210, prev_p, -+ Q_NEXT_TYPE(fotg210, *hw_p)); -+ hw_p = shadow_next_periodic(fotg210, &here, -+ Q_NEXT_TYPE(fotg210, *hw_p)); -+ here = *prev_p; -+ } -+ /* an interrupt entry (at list end) could have been shared */ -+ if (!here.ptr) -+ return; -+ -+ /* update shadow and hardware lists ... the old "next" pointers -+ * from ptr may still be in use, the caller updates them. -+ */ -+ *prev_p = *periodic_next_shadow(fotg210, &here, -+ Q_NEXT_TYPE(fotg210, *hw_p)); -+ -+ *hw_p = *shadow_next_periodic(fotg210, &here, -+ Q_NEXT_TYPE(fotg210, *hw_p)); -+} -+ -+/* how many of the uframe's 125 usecs are allocated? */ -+static unsigned short periodic_usecs(struct fotg210_hcd *fotg210, -+ unsigned frame, unsigned uframe) -+{ -+ __hc32 *hw_p = &fotg210->periodic[frame]; -+ union fotg210_shadow *q = &fotg210->pshadow[frame]; -+ unsigned usecs = 0; -+ struct fotg210_qh_hw *hw; -+ -+ while (q->ptr) { -+ switch (hc32_to_cpu(fotg210, Q_NEXT_TYPE(fotg210, *hw_p))) { -+ case Q_TYPE_QH: -+ hw = q->qh->hw; -+ /* is it in the S-mask? */ -+ if (hw->hw_info2 & cpu_to_hc32(fotg210, 1 << uframe)) -+ usecs += q->qh->usecs; -+ /* ... or C-mask? */ -+ if (hw->hw_info2 & cpu_to_hc32(fotg210, -+ 1 << (8 + uframe))) -+ usecs += q->qh->c_usecs; -+ hw_p = &hw->hw_next; -+ q = &q->qh->qh_next; -+ break; -+ /* case Q_TYPE_FSTN: */ -+ default: -+ /* for "save place" FSTNs, count the relevant INTR -+ * bandwidth from the previous frame -+ */ -+ if (q->fstn->hw_prev != FOTG210_LIST_END(fotg210)) -+ fotg210_dbg(fotg210, "ignoring FSTN cost ...\n"); -+ -+ hw_p = &q->fstn->hw_next; -+ q = &q->fstn->fstn_next; -+ break; -+ case Q_TYPE_ITD: -+ if (q->itd->hw_transaction[uframe]) -+ usecs += q->itd->stream->usecs; -+ hw_p = &q->itd->hw_next; -+ q = &q->itd->itd_next; -+ break; -+ } -+ } -+ if (usecs > fotg210->uframe_periodic_max) -+ fotg210_err(fotg210, "uframe %d sched overrun: %d usecs\n", -+ frame * 8 + uframe, usecs); -+ return usecs; -+} -+ -+static int same_tt(struct usb_device *dev1, struct usb_device *dev2) -+{ -+ if (!dev1->tt || !dev2->tt) -+ return 0; -+ if (dev1->tt != dev2->tt) -+ return 0; -+ if (dev1->tt->multi) -+ return dev1->ttport == dev2->ttport; -+ else -+ return 1; -+} -+ -+/* return true iff the device's transaction translator is available -+ * for a periodic transfer starting at the specified frame, using -+ * all the uframes in the mask. -+ */ -+static int tt_no_collision(struct fotg210_hcd *fotg210, unsigned period, -+ struct usb_device *dev, unsigned frame, u32 uf_mask) -+{ -+ if (period == 0) /* error */ -+ return 0; -+ -+ /* note bandwidth wastage: split never follows csplit -+ * (different dev or endpoint) until the next uframe. -+ * calling convention doesn't make that distinction. -+ */ -+ for (; frame < fotg210->periodic_size; frame += period) { -+ union fotg210_shadow here; -+ __hc32 type; -+ struct fotg210_qh_hw *hw; -+ -+ here = fotg210->pshadow[frame]; -+ type = Q_NEXT_TYPE(fotg210, fotg210->periodic[frame]); -+ while (here.ptr) { -+ switch (hc32_to_cpu(fotg210, type)) { -+ case Q_TYPE_ITD: -+ type = Q_NEXT_TYPE(fotg210, here.itd->hw_next); -+ here = here.itd->itd_next; -+ continue; -+ case Q_TYPE_QH: -+ hw = here.qh->hw; -+ if (same_tt(dev, here.qh->dev)) { -+ u32 mask; -+ -+ mask = hc32_to_cpu(fotg210, -+ hw->hw_info2); -+ /* "knows" no gap is needed */ -+ mask |= mask >> 8; -+ if (mask & uf_mask) -+ break; -+ } -+ type = Q_NEXT_TYPE(fotg210, hw->hw_next); -+ here = here.qh->qh_next; -+ continue; -+ /* case Q_TYPE_FSTN: */ -+ default: -+ fotg210_dbg(fotg210, -+ "periodic frame %d bogus type %d\n", -+ frame, type); -+ } -+ -+ /* collision or error */ -+ return 0; -+ } -+ } -+ -+ /* no collision */ -+ return 1; -+} -+ -+static void enable_periodic(struct fotg210_hcd *fotg210) -+{ -+ if (fotg210->periodic_count++) -+ return; -+ -+ /* Stop waiting to turn off the periodic schedule */ -+ fotg210->enabled_hrtimer_events &= -+ ~BIT(FOTG210_HRTIMER_DISABLE_PERIODIC); -+ -+ /* Don't start the schedule until PSS is 0 */ -+ fotg210_poll_PSS(fotg210); -+ turn_on_io_watchdog(fotg210); -+} -+ -+static void disable_periodic(struct fotg210_hcd *fotg210) -+{ -+ if (--fotg210->periodic_count) -+ return; -+ -+ /* Don't turn off the schedule until PSS is 1 */ -+ fotg210_poll_PSS(fotg210); -+} -+ -+/* periodic schedule slots have iso tds (normal or split) first, then a -+ * sparse tree for active interrupt transfers. -+ * -+ * this just links in a qh; caller guarantees uframe masks are set right. -+ * no FSTN support (yet; fotg210 0.96+) -+ */ -+static void qh_link_periodic(struct fotg210_hcd *fotg210, struct fotg210_qh *qh) -+{ -+ unsigned i; -+ unsigned period = qh->period; -+ -+ dev_dbg(&qh->dev->dev, -+ "link qh%d-%04x/%p start %d [%d/%d us]\n", period, -+ hc32_to_cpup(fotg210, &qh->hw->hw_info2) & -+ (QH_CMASK | QH_SMASK), qh, qh->start, qh->usecs, -+ qh->c_usecs); -+ -+ /* high bandwidth, or otherwise every microframe */ -+ if (period == 0) -+ period = 1; -+ -+ for (i = qh->start; i < fotg210->periodic_size; i += period) { -+ union fotg210_shadow *prev = &fotg210->pshadow[i]; -+ __hc32 *hw_p = &fotg210->periodic[i]; -+ union fotg210_shadow here = *prev; -+ __hc32 type = 0; -+ -+ /* skip the iso nodes at list head */ -+ while (here.ptr) { -+ type = Q_NEXT_TYPE(fotg210, *hw_p); -+ if (type == cpu_to_hc32(fotg210, Q_TYPE_QH)) -+ break; -+ prev = periodic_next_shadow(fotg210, prev, type); -+ hw_p = shadow_next_periodic(fotg210, &here, type); -+ here = *prev; -+ } -+ -+ /* sorting each branch by period (slow-->fast) -+ * enables sharing interior tree nodes -+ */ -+ while (here.ptr && qh != here.qh) { -+ if (qh->period > here.qh->period) -+ break; -+ prev = &here.qh->qh_next; -+ hw_p = &here.qh->hw->hw_next; -+ here = *prev; -+ } -+ /* link in this qh, unless some earlier pass did that */ -+ if (qh != here.qh) { -+ qh->qh_next = here; -+ if (here.qh) -+ qh->hw->hw_next = *hw_p; -+ wmb(); -+ prev->qh = qh; -+ *hw_p = QH_NEXT(fotg210, qh->qh_dma); -+ } -+ } -+ qh->qh_state = QH_STATE_LINKED; -+ qh->xacterrs = 0; -+ -+ /* update per-qh bandwidth for usbfs */ -+ fotg210_to_hcd(fotg210)->self.bandwidth_allocated += qh->period -+ ? ((qh->usecs + qh->c_usecs) / qh->period) -+ : (qh->usecs * 8); -+ -+ list_add(&qh->intr_node, &fotg210->intr_qh_list); -+ -+ /* maybe enable periodic schedule processing */ -+ ++fotg210->intr_count; -+ enable_periodic(fotg210); -+} -+ -+static void qh_unlink_periodic(struct fotg210_hcd *fotg210, -+ struct fotg210_qh *qh) -+{ -+ unsigned i; -+ unsigned period; -+ -+ /* -+ * If qh is for a low/full-speed device, simply unlinking it -+ * could interfere with an ongoing split transaction. To unlink -+ * it safely would require setting the QH_INACTIVATE bit and -+ * waiting at least one frame, as described in EHCI 4.12.2.5. -+ * -+ * We won't bother with any of this. Instead, we assume that the -+ * only reason for unlinking an interrupt QH while the current URB -+ * is still active is to dequeue all the URBs (flush the whole -+ * endpoint queue). -+ * -+ * If rebalancing the periodic schedule is ever implemented, this -+ * approach will no longer be valid. -+ */ -+ -+ /* high bandwidth, or otherwise part of every microframe */ -+ period = qh->period; -+ if (!period) -+ period = 1; -+ -+ for (i = qh->start; i < fotg210->periodic_size; i += period) -+ periodic_unlink(fotg210, i, qh); -+ -+ /* update per-qh bandwidth for usbfs */ -+ fotg210_to_hcd(fotg210)->self.bandwidth_allocated -= qh->period -+ ? ((qh->usecs + qh->c_usecs) / qh->period) -+ : (qh->usecs * 8); -+ -+ dev_dbg(&qh->dev->dev, -+ "unlink qh%d-%04x/%p start %d [%d/%d us]\n", -+ qh->period, hc32_to_cpup(fotg210, &qh->hw->hw_info2) & -+ (QH_CMASK | QH_SMASK), qh, qh->start, qh->usecs, -+ qh->c_usecs); -+ -+ /* qh->qh_next still "live" to HC */ -+ qh->qh_state = QH_STATE_UNLINK; -+ qh->qh_next.ptr = NULL; -+ -+ if (fotg210->qh_scan_next == qh) -+ fotg210->qh_scan_next = list_entry(qh->intr_node.next, -+ struct fotg210_qh, intr_node); -+ list_del(&qh->intr_node); -+} -+ -+static void start_unlink_intr(struct fotg210_hcd *fotg210, -+ struct fotg210_qh *qh) -+{ -+ /* If the QH isn't linked then there's nothing we can do -+ * unless we were called during a giveback, in which case -+ * qh_completions() has to deal with it. -+ */ -+ if (qh->qh_state != QH_STATE_LINKED) { -+ if (qh->qh_state == QH_STATE_COMPLETING) -+ qh->needs_rescan = 1; -+ return; -+ } -+ -+ qh_unlink_periodic(fotg210, qh); -+ -+ /* Make sure the unlinks are visible before starting the timer */ -+ wmb(); -+ -+ /* -+ * The EHCI spec doesn't say how long it takes the controller to -+ * stop accessing an unlinked interrupt QH. The timer delay is -+ * 9 uframes; presumably that will be long enough. -+ */ -+ qh->unlink_cycle = fotg210->intr_unlink_cycle; -+ -+ /* New entries go at the end of the intr_unlink list */ -+ if (fotg210->intr_unlink) -+ fotg210->intr_unlink_last->unlink_next = qh; -+ else -+ fotg210->intr_unlink = qh; -+ fotg210->intr_unlink_last = qh; -+ -+ if (fotg210->intr_unlinking) -+ ; /* Avoid recursive calls */ -+ else if (fotg210->rh_state < FOTG210_RH_RUNNING) -+ fotg210_handle_intr_unlinks(fotg210); -+ else if (fotg210->intr_unlink == qh) { -+ fotg210_enable_event(fotg210, FOTG210_HRTIMER_UNLINK_INTR, -+ true); -+ ++fotg210->intr_unlink_cycle; -+ } -+} -+ -+static void end_unlink_intr(struct fotg210_hcd *fotg210, struct fotg210_qh *qh) -+{ -+ struct fotg210_qh_hw *hw = qh->hw; -+ int rc; -+ -+ qh->qh_state = QH_STATE_IDLE; -+ hw->hw_next = FOTG210_LIST_END(fotg210); -+ -+ qh_completions(fotg210, qh); -+ -+ /* reschedule QH iff another request is queued */ -+ if (!list_empty(&qh->qtd_list) && -+ fotg210->rh_state == FOTG210_RH_RUNNING) { -+ rc = qh_schedule(fotg210, qh); -+ -+ /* An error here likely indicates handshake failure -+ * or no space left in the schedule. Neither fault -+ * should happen often ... -+ * -+ * FIXME kill the now-dysfunctional queued urbs -+ */ -+ if (rc != 0) -+ fotg210_err(fotg210, "can't reschedule qh %p, err %d\n", -+ qh, rc); -+ } -+ -+ /* maybe turn off periodic schedule */ -+ --fotg210->intr_count; -+ disable_periodic(fotg210); -+} -+ -+static int check_period(struct fotg210_hcd *fotg210, unsigned frame, -+ unsigned uframe, unsigned period, unsigned usecs) -+{ -+ int claimed; -+ -+ /* complete split running into next frame? -+ * given FSTN support, we could sometimes check... -+ */ -+ if (uframe >= 8) -+ return 0; -+ -+ /* convert "usecs we need" to "max already claimed" */ -+ usecs = fotg210->uframe_periodic_max - usecs; -+ -+ /* we "know" 2 and 4 uframe intervals were rejected; so -+ * for period 0, check _every_ microframe in the schedule. -+ */ -+ if (unlikely(period == 0)) { -+ do { -+ for (uframe = 0; uframe < 7; uframe++) { -+ claimed = periodic_usecs(fotg210, frame, -+ uframe); -+ if (claimed > usecs) -+ return 0; -+ } -+ } while ((frame += 1) < fotg210->periodic_size); -+ -+ /* just check the specified uframe, at that period */ -+ } else { -+ do { -+ claimed = periodic_usecs(fotg210, frame, uframe); -+ if (claimed > usecs) -+ return 0; -+ } while ((frame += period) < fotg210->periodic_size); -+ } -+ -+ /* success! */ -+ return 1; -+} -+ -+static int check_intr_schedule(struct fotg210_hcd *fotg210, unsigned frame, -+ unsigned uframe, const struct fotg210_qh *qh, __hc32 *c_maskp) -+{ -+ int retval = -ENOSPC; -+ u8 mask = 0; -+ -+ if (qh->c_usecs && uframe >= 6) /* FSTN territory? */ -+ goto done; -+ -+ if (!check_period(fotg210, frame, uframe, qh->period, qh->usecs)) -+ goto done; -+ if (!qh->c_usecs) { -+ retval = 0; -+ *c_maskp = 0; -+ goto done; -+ } -+ -+ /* Make sure this tt's buffer is also available for CSPLITs. -+ * We pessimize a bit; probably the typical full speed case -+ * doesn't need the second CSPLIT. -+ * -+ * NOTE: both SPLIT and CSPLIT could be checked in just -+ * one smart pass... -+ */ -+ mask = 0x03 << (uframe + qh->gap_uf); -+ *c_maskp = cpu_to_hc32(fotg210, mask << 8); -+ -+ mask |= 1 << uframe; -+ if (tt_no_collision(fotg210, qh->period, qh->dev, frame, mask)) { -+ if (!check_period(fotg210, frame, uframe + qh->gap_uf + 1, -+ qh->period, qh->c_usecs)) -+ goto done; -+ if (!check_period(fotg210, frame, uframe + qh->gap_uf, -+ qh->period, qh->c_usecs)) -+ goto done; -+ retval = 0; -+ } -+done: -+ return retval; -+} -+ -+/* "first fit" scheduling policy used the first time through, -+ * or when the previous schedule slot can't be re-used. -+ */ -+static int qh_schedule(struct fotg210_hcd *fotg210, struct fotg210_qh *qh) -+{ -+ int status; -+ unsigned uframe; -+ __hc32 c_mask; -+ unsigned frame; /* 0..(qh->period - 1), or NO_FRAME */ -+ struct fotg210_qh_hw *hw = qh->hw; -+ -+ qh_refresh(fotg210, qh); -+ hw->hw_next = FOTG210_LIST_END(fotg210); -+ frame = qh->start; -+ -+ /* reuse the previous schedule slots, if we can */ -+ if (frame < qh->period) { -+ uframe = ffs(hc32_to_cpup(fotg210, &hw->hw_info2) & QH_SMASK); -+ status = check_intr_schedule(fotg210, frame, --uframe, -+ qh, &c_mask); -+ } else { -+ uframe = 0; -+ c_mask = 0; -+ status = -ENOSPC; -+ } -+ -+ /* else scan the schedule to find a group of slots such that all -+ * uframes have enough periodic bandwidth available. -+ */ -+ if (status) { -+ /* "normal" case, uframing flexible except with splits */ -+ if (qh->period) { -+ int i; -+ -+ for (i = qh->period; status && i > 0; --i) { -+ frame = ++fotg210->random_frame % qh->period; -+ for (uframe = 0; uframe < 8; uframe++) { -+ status = check_intr_schedule(fotg210, -+ frame, uframe, qh, -+ &c_mask); -+ if (status == 0) -+ break; -+ } -+ } -+ -+ /* qh->period == 0 means every uframe */ -+ } else { -+ frame = 0; -+ status = check_intr_schedule(fotg210, 0, 0, qh, -+ &c_mask); -+ } -+ if (status) -+ goto done; -+ qh->start = frame; -+ -+ /* reset S-frame and (maybe) C-frame masks */ -+ hw->hw_info2 &= cpu_to_hc32(fotg210, ~(QH_CMASK | QH_SMASK)); -+ hw->hw_info2 |= qh->period -+ ? cpu_to_hc32(fotg210, 1 << uframe) -+ : cpu_to_hc32(fotg210, QH_SMASK); -+ hw->hw_info2 |= c_mask; -+ } else -+ fotg210_dbg(fotg210, "reused qh %p schedule\n", qh); -+ -+ /* stuff into the periodic schedule */ -+ qh_link_periodic(fotg210, qh); -+done: -+ return status; -+} -+ -+static int intr_submit(struct fotg210_hcd *fotg210, struct urb *urb, -+ struct list_head *qtd_list, gfp_t mem_flags) -+{ -+ unsigned epnum; -+ unsigned long flags; -+ struct fotg210_qh *qh; -+ int status; -+ struct list_head empty; -+ -+ /* get endpoint and transfer/schedule data */ -+ epnum = urb->ep->desc.bEndpointAddress; -+ -+ spin_lock_irqsave(&fotg210->lock, flags); -+ -+ if (unlikely(!HCD_HW_ACCESSIBLE(fotg210_to_hcd(fotg210)))) { -+ status = -ESHUTDOWN; -+ goto done_not_linked; -+ } -+ status = usb_hcd_link_urb_to_ep(fotg210_to_hcd(fotg210), urb); -+ if (unlikely(status)) -+ goto done_not_linked; -+ -+ /* get qh and force any scheduling errors */ -+ INIT_LIST_HEAD(&empty); -+ qh = qh_append_tds(fotg210, urb, &empty, epnum, &urb->ep->hcpriv); -+ if (qh == NULL) { -+ status = -ENOMEM; -+ goto done; -+ } -+ if (qh->qh_state == QH_STATE_IDLE) { -+ status = qh_schedule(fotg210, qh); -+ if (status) -+ goto done; -+ } -+ -+ /* then queue the urb's tds to the qh */ -+ qh = qh_append_tds(fotg210, urb, qtd_list, epnum, &urb->ep->hcpriv); -+ BUG_ON(qh == NULL); -+ -+ /* ... update usbfs periodic stats */ -+ fotg210_to_hcd(fotg210)->self.bandwidth_int_reqs++; -+ -+done: -+ if (unlikely(status)) -+ usb_hcd_unlink_urb_from_ep(fotg210_to_hcd(fotg210), urb); -+done_not_linked: -+ spin_unlock_irqrestore(&fotg210->lock, flags); -+ if (status) -+ qtd_list_free(fotg210, urb, qtd_list); -+ -+ return status; -+} -+ -+static void scan_intr(struct fotg210_hcd *fotg210) -+{ -+ struct fotg210_qh *qh; -+ -+ list_for_each_entry_safe(qh, fotg210->qh_scan_next, -+ &fotg210->intr_qh_list, intr_node) { -+rescan: -+ /* clean any finished work for this qh */ -+ if (!list_empty(&qh->qtd_list)) { -+ int temp; -+ -+ /* -+ * Unlinks could happen here; completion reporting -+ * drops the lock. That's why fotg210->qh_scan_next -+ * always holds the next qh to scan; if the next qh -+ * gets unlinked then fotg210->qh_scan_next is adjusted -+ * in qh_unlink_periodic(). -+ */ -+ temp = qh_completions(fotg210, qh); -+ if (unlikely(qh->needs_rescan || -+ (list_empty(&qh->qtd_list) && -+ qh->qh_state == QH_STATE_LINKED))) -+ start_unlink_intr(fotg210, qh); -+ else if (temp != 0) -+ goto rescan; -+ } -+ } -+} -+ -+/* fotg210_iso_stream ops work with both ITD and SITD */ -+ -+static struct fotg210_iso_stream *iso_stream_alloc(gfp_t mem_flags) -+{ -+ struct fotg210_iso_stream *stream; -+ -+ stream = kzalloc(sizeof(*stream), mem_flags); -+ if (likely(stream != NULL)) { -+ INIT_LIST_HEAD(&stream->td_list); -+ INIT_LIST_HEAD(&stream->free_list); -+ stream->next_uframe = -1; -+ } -+ return stream; -+} -+ -+static void iso_stream_init(struct fotg210_hcd *fotg210, -+ struct fotg210_iso_stream *stream, struct usb_device *dev, -+ int pipe, unsigned interval) -+{ -+ u32 buf1; -+ unsigned epnum, maxp; -+ int is_input; -+ long bandwidth; -+ unsigned multi; -+ struct usb_host_endpoint *ep; -+ -+ /* -+ * this might be a "high bandwidth" highspeed endpoint, -+ * as encoded in the ep descriptor's wMaxPacket field -+ */ -+ epnum = usb_pipeendpoint(pipe); -+ is_input = usb_pipein(pipe) ? USB_DIR_IN : 0; -+ ep = usb_pipe_endpoint(dev, pipe); -+ maxp = usb_endpoint_maxp(&ep->desc); -+ if (is_input) -+ buf1 = (1 << 11); -+ else -+ buf1 = 0; -+ -+ multi = usb_endpoint_maxp_mult(&ep->desc); -+ buf1 |= maxp; -+ maxp *= multi; -+ -+ stream->buf0 = cpu_to_hc32(fotg210, (epnum << 8) | dev->devnum); -+ stream->buf1 = cpu_to_hc32(fotg210, buf1); -+ stream->buf2 = cpu_to_hc32(fotg210, multi); -+ -+ /* usbfs wants to report the average usecs per frame tied up -+ * when transfers on this endpoint are scheduled ... -+ */ -+ if (dev->speed == USB_SPEED_FULL) { -+ interval <<= 3; -+ stream->usecs = NS_TO_US(usb_calc_bus_time(dev->speed, -+ is_input, 1, maxp)); -+ stream->usecs /= 8; -+ } else { -+ stream->highspeed = 1; -+ stream->usecs = HS_USECS_ISO(maxp); -+ } -+ bandwidth = stream->usecs * 8; -+ bandwidth /= interval; -+ -+ stream->bandwidth = bandwidth; -+ stream->udev = dev; -+ stream->bEndpointAddress = is_input | epnum; -+ stream->interval = interval; -+ stream->maxp = maxp; -+} -+ -+static struct fotg210_iso_stream *iso_stream_find(struct fotg210_hcd *fotg210, -+ struct urb *urb) -+{ -+ unsigned epnum; -+ struct fotg210_iso_stream *stream; -+ struct usb_host_endpoint *ep; -+ unsigned long flags; -+ -+ epnum = usb_pipeendpoint(urb->pipe); -+ if (usb_pipein(urb->pipe)) -+ ep = urb->dev->ep_in[epnum]; -+ else -+ ep = urb->dev->ep_out[epnum]; -+ -+ spin_lock_irqsave(&fotg210->lock, flags); -+ stream = ep->hcpriv; -+ -+ if (unlikely(stream == NULL)) { -+ stream = iso_stream_alloc(GFP_ATOMIC); -+ if (likely(stream != NULL)) { -+ ep->hcpriv = stream; -+ stream->ep = ep; -+ iso_stream_init(fotg210, stream, urb->dev, urb->pipe, -+ urb->interval); -+ } -+ -+ /* if dev->ep[epnum] is a QH, hw is set */ -+ } else if (unlikely(stream->hw != NULL)) { -+ fotg210_dbg(fotg210, "dev %s ep%d%s, not iso??\n", -+ urb->dev->devpath, epnum, -+ usb_pipein(urb->pipe) ? "in" : "out"); -+ stream = NULL; -+ } -+ -+ spin_unlock_irqrestore(&fotg210->lock, flags); -+ return stream; -+} -+ -+/* fotg210_iso_sched ops can be ITD-only or SITD-only */ -+ -+static struct fotg210_iso_sched *iso_sched_alloc(unsigned packets, -+ gfp_t mem_flags) -+{ -+ struct fotg210_iso_sched *iso_sched; -+ -+ iso_sched = kzalloc(struct_size(iso_sched, packet, packets), mem_flags); -+ if (likely(iso_sched != NULL)) -+ INIT_LIST_HEAD(&iso_sched->td_list); -+ -+ return iso_sched; -+} -+ -+static inline void itd_sched_init(struct fotg210_hcd *fotg210, -+ struct fotg210_iso_sched *iso_sched, -+ struct fotg210_iso_stream *stream, struct urb *urb) -+{ -+ unsigned i; -+ dma_addr_t dma = urb->transfer_dma; -+ -+ /* how many uframes are needed for these transfers */ -+ iso_sched->span = urb->number_of_packets * stream->interval; -+ -+ /* figure out per-uframe itd fields that we'll need later -+ * when we fit new itds into the schedule. -+ */ -+ for (i = 0; i < urb->number_of_packets; i++) { -+ struct fotg210_iso_packet *uframe = &iso_sched->packet[i]; -+ unsigned length; -+ dma_addr_t buf; -+ u32 trans; -+ -+ length = urb->iso_frame_desc[i].length; -+ buf = dma + urb->iso_frame_desc[i].offset; -+ -+ trans = FOTG210_ISOC_ACTIVE; -+ trans |= buf & 0x0fff; -+ if (unlikely(((i + 1) == urb->number_of_packets)) -+ && !(urb->transfer_flags & URB_NO_INTERRUPT)) -+ trans |= FOTG210_ITD_IOC; -+ trans |= length << 16; -+ uframe->transaction = cpu_to_hc32(fotg210, trans); -+ -+ /* might need to cross a buffer page within a uframe */ -+ uframe->bufp = (buf & ~(u64)0x0fff); -+ buf += length; -+ if (unlikely((uframe->bufp != (buf & ~(u64)0x0fff)))) -+ uframe->cross = 1; -+ } -+} -+ -+static void iso_sched_free(struct fotg210_iso_stream *stream, -+ struct fotg210_iso_sched *iso_sched) -+{ -+ if (!iso_sched) -+ return; -+ /* caller must hold fotg210->lock!*/ -+ list_splice(&iso_sched->td_list, &stream->free_list); -+ kfree(iso_sched); -+} -+ -+static int itd_urb_transaction(struct fotg210_iso_stream *stream, -+ struct fotg210_hcd *fotg210, struct urb *urb, gfp_t mem_flags) -+{ -+ struct fotg210_itd *itd; -+ dma_addr_t itd_dma; -+ int i; -+ unsigned num_itds; -+ struct fotg210_iso_sched *sched; -+ unsigned long flags; -+ -+ sched = iso_sched_alloc(urb->number_of_packets, mem_flags); -+ if (unlikely(sched == NULL)) -+ return -ENOMEM; -+ -+ itd_sched_init(fotg210, sched, stream, urb); -+ -+ if (urb->interval < 8) -+ num_itds = 1 + (sched->span + 7) / 8; -+ else -+ num_itds = urb->number_of_packets; -+ -+ /* allocate/init ITDs */ -+ spin_lock_irqsave(&fotg210->lock, flags); -+ for (i = 0; i < num_itds; i++) { -+ -+ /* -+ * Use iTDs from the free list, but not iTDs that may -+ * still be in use by the hardware. -+ */ -+ if (likely(!list_empty(&stream->free_list))) { -+ itd = list_first_entry(&stream->free_list, -+ struct fotg210_itd, itd_list); -+ if (itd->frame == fotg210->now_frame) -+ goto alloc_itd; -+ list_del(&itd->itd_list); -+ itd_dma = itd->itd_dma; -+ } else { -+alloc_itd: -+ spin_unlock_irqrestore(&fotg210->lock, flags); -+ itd = dma_pool_alloc(fotg210->itd_pool, mem_flags, -+ &itd_dma); -+ spin_lock_irqsave(&fotg210->lock, flags); -+ if (!itd) { -+ iso_sched_free(stream, sched); -+ spin_unlock_irqrestore(&fotg210->lock, flags); -+ return -ENOMEM; -+ } -+ } -+ -+ memset(itd, 0, sizeof(*itd)); -+ itd->itd_dma = itd_dma; -+ list_add(&itd->itd_list, &sched->td_list); -+ } -+ spin_unlock_irqrestore(&fotg210->lock, flags); -+ -+ /* temporarily store schedule info in hcpriv */ -+ urb->hcpriv = sched; -+ urb->error_count = 0; -+ return 0; -+} -+ -+static inline int itd_slot_ok(struct fotg210_hcd *fotg210, u32 mod, u32 uframe, -+ u8 usecs, u32 period) -+{ -+ uframe %= period; -+ do { -+ /* can't commit more than uframe_periodic_max usec */ -+ if (periodic_usecs(fotg210, uframe >> 3, uframe & 0x7) -+ > (fotg210->uframe_periodic_max - usecs)) -+ return 0; -+ -+ /* we know urb->interval is 2^N uframes */ -+ uframe += period; -+ } while (uframe < mod); -+ return 1; -+} -+ -+/* This scheduler plans almost as far into the future as it has actual -+ * periodic schedule slots. (Affected by TUNE_FLS, which defaults to -+ * "as small as possible" to be cache-friendlier.) That limits the size -+ * transfers you can stream reliably; avoid more than 64 msec per urb. -+ * Also avoid queue depths of less than fotg210's worst irq latency (affected -+ * by the per-urb URB_NO_INTERRUPT hint, the log2_irq_thresh module parameter, -+ * and other factors); or more than about 230 msec total (for portability, -+ * given FOTG210_TUNE_FLS and the slop). Or, write a smarter scheduler! -+ */ -+ -+#define SCHEDULE_SLOP 80 /* microframes */ -+ -+static int iso_stream_schedule(struct fotg210_hcd *fotg210, struct urb *urb, -+ struct fotg210_iso_stream *stream) -+{ -+ u32 now, next, start, period, span; -+ int status; -+ unsigned mod = fotg210->periodic_size << 3; -+ struct fotg210_iso_sched *sched = urb->hcpriv; -+ -+ period = urb->interval; -+ span = sched->span; -+ -+ if (span > mod - SCHEDULE_SLOP) { -+ fotg210_dbg(fotg210, "iso request %p too long\n", urb); -+ status = -EFBIG; -+ goto fail; -+ } -+ -+ now = fotg210_read_frame_index(fotg210) & (mod - 1); -+ -+ /* Typical case: reuse current schedule, stream is still active. -+ * Hopefully there are no gaps from the host falling behind -+ * (irq delays etc), but if there are we'll take the next -+ * slot in the schedule, implicitly assuming URB_ISO_ASAP. -+ */ -+ if (likely(!list_empty(&stream->td_list))) { -+ u32 excess; -+ -+ /* For high speed devices, allow scheduling within the -+ * isochronous scheduling threshold. For full speed devices -+ * and Intel PCI-based controllers, don't (work around for -+ * Intel ICH9 bug). -+ */ -+ if (!stream->highspeed && fotg210->fs_i_thresh) -+ next = now + fotg210->i_thresh; -+ else -+ next = now; -+ -+ /* Fell behind (by up to twice the slop amount)? -+ * We decide based on the time of the last currently-scheduled -+ * slot, not the time of the next available slot. -+ */ -+ excess = (stream->next_uframe - period - next) & (mod - 1); -+ if (excess >= mod - 2 * SCHEDULE_SLOP) -+ start = next + excess - mod + period * -+ DIV_ROUND_UP(mod - excess, period); -+ else -+ start = next + excess + period; -+ if (start - now >= mod) { -+ fotg210_dbg(fotg210, "request %p would overflow (%d+%d >= %d)\n", -+ urb, start - now - period, period, -+ mod); -+ status = -EFBIG; -+ goto fail; -+ } -+ } -+ -+ /* need to schedule; when's the next (u)frame we could start? -+ * this is bigger than fotg210->i_thresh allows; scheduling itself -+ * isn't free, the slop should handle reasonably slow cpus. it -+ * can also help high bandwidth if the dma and irq loads don't -+ * jump until after the queue is primed. -+ */ -+ else { -+ int done = 0; -+ -+ start = SCHEDULE_SLOP + (now & ~0x07); -+ -+ /* NOTE: assumes URB_ISO_ASAP, to limit complexity/bugs */ -+ -+ /* find a uframe slot with enough bandwidth. -+ * Early uframes are more precious because full-speed -+ * iso IN transfers can't use late uframes, -+ * and therefore they should be allocated last. -+ */ -+ next = start; -+ start += period; -+ do { -+ start--; -+ /* check schedule: enough space? */ -+ if (itd_slot_ok(fotg210, mod, start, -+ stream->usecs, period)) -+ done = 1; -+ } while (start > next && !done); -+ -+ /* no room in the schedule */ -+ if (!done) { -+ fotg210_dbg(fotg210, "iso resched full %p (now %d max %d)\n", -+ urb, now, now + mod); -+ status = -ENOSPC; -+ goto fail; -+ } -+ } -+ -+ /* Tried to schedule too far into the future? */ -+ if (unlikely(start - now + span - period >= -+ mod - 2 * SCHEDULE_SLOP)) { -+ fotg210_dbg(fotg210, "request %p would overflow (%d+%d >= %d)\n", -+ urb, start - now, span - period, -+ mod - 2 * SCHEDULE_SLOP); -+ status = -EFBIG; -+ goto fail; -+ } -+ -+ stream->next_uframe = start & (mod - 1); -+ -+ /* report high speed start in uframes; full speed, in frames */ -+ urb->start_frame = stream->next_uframe; -+ if (!stream->highspeed) -+ urb->start_frame >>= 3; -+ -+ /* Make sure scan_isoc() sees these */ -+ if (fotg210->isoc_count == 0) -+ fotg210->next_frame = now >> 3; -+ return 0; -+ -+fail: -+ iso_sched_free(stream, sched); -+ urb->hcpriv = NULL; -+ return status; -+} -+ -+static inline void itd_init(struct fotg210_hcd *fotg210, -+ struct fotg210_iso_stream *stream, struct fotg210_itd *itd) -+{ -+ int i; -+ -+ /* it's been recently zeroed */ -+ itd->hw_next = FOTG210_LIST_END(fotg210); -+ itd->hw_bufp[0] = stream->buf0; -+ itd->hw_bufp[1] = stream->buf1; -+ itd->hw_bufp[2] = stream->buf2; -+ -+ for (i = 0; i < 8; i++) -+ itd->index[i] = -1; -+ -+ /* All other fields are filled when scheduling */ -+} -+ -+static inline void itd_patch(struct fotg210_hcd *fotg210, -+ struct fotg210_itd *itd, struct fotg210_iso_sched *iso_sched, -+ unsigned index, u16 uframe) -+{ -+ struct fotg210_iso_packet *uf = &iso_sched->packet[index]; -+ unsigned pg = itd->pg; -+ -+ uframe &= 0x07; -+ itd->index[uframe] = index; -+ -+ itd->hw_transaction[uframe] = uf->transaction; -+ itd->hw_transaction[uframe] |= cpu_to_hc32(fotg210, pg << 12); -+ itd->hw_bufp[pg] |= cpu_to_hc32(fotg210, uf->bufp & ~(u32)0); -+ itd->hw_bufp_hi[pg] |= cpu_to_hc32(fotg210, (u32)(uf->bufp >> 32)); -+ -+ /* iso_frame_desc[].offset must be strictly increasing */ -+ if (unlikely(uf->cross)) { -+ u64 bufp = uf->bufp + 4096; -+ -+ itd->pg = ++pg; -+ itd->hw_bufp[pg] |= cpu_to_hc32(fotg210, bufp & ~(u32)0); -+ itd->hw_bufp_hi[pg] |= cpu_to_hc32(fotg210, (u32)(bufp >> 32)); -+ } -+} -+ -+static inline void itd_link(struct fotg210_hcd *fotg210, unsigned frame, -+ struct fotg210_itd *itd) -+{ -+ union fotg210_shadow *prev = &fotg210->pshadow[frame]; -+ __hc32 *hw_p = &fotg210->periodic[frame]; -+ union fotg210_shadow here = *prev; -+ __hc32 type = 0; -+ -+ /* skip any iso nodes which might belong to previous microframes */ -+ while (here.ptr) { -+ type = Q_NEXT_TYPE(fotg210, *hw_p); -+ if (type == cpu_to_hc32(fotg210, Q_TYPE_QH)) -+ break; -+ prev = periodic_next_shadow(fotg210, prev, type); -+ hw_p = shadow_next_periodic(fotg210, &here, type); -+ here = *prev; -+ } -+ -+ itd->itd_next = here; -+ itd->hw_next = *hw_p; -+ prev->itd = itd; -+ itd->frame = frame; -+ wmb(); -+ *hw_p = cpu_to_hc32(fotg210, itd->itd_dma | Q_TYPE_ITD); -+} -+ -+/* fit urb's itds into the selected schedule slot; activate as needed */ -+static void itd_link_urb(struct fotg210_hcd *fotg210, struct urb *urb, -+ unsigned mod, struct fotg210_iso_stream *stream) -+{ -+ int packet; -+ unsigned next_uframe, uframe, frame; -+ struct fotg210_iso_sched *iso_sched = urb->hcpriv; -+ struct fotg210_itd *itd; -+ -+ next_uframe = stream->next_uframe & (mod - 1); -+ -+ if (unlikely(list_empty(&stream->td_list))) { -+ fotg210_to_hcd(fotg210)->self.bandwidth_allocated -+ += stream->bandwidth; -+ fotg210_dbg(fotg210, -+ "schedule devp %s ep%d%s-iso period %d start %d.%d\n", -+ urb->dev->devpath, stream->bEndpointAddress & 0x0f, -+ (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out", -+ urb->interval, -+ next_uframe >> 3, next_uframe & 0x7); -+ } -+ -+ /* fill iTDs uframe by uframe */ -+ for (packet = 0, itd = NULL; packet < urb->number_of_packets;) { -+ if (itd == NULL) { -+ /* ASSERT: we have all necessary itds */ -+ -+ /* ASSERT: no itds for this endpoint in this uframe */ -+ -+ itd = list_entry(iso_sched->td_list.next, -+ struct fotg210_itd, itd_list); -+ list_move_tail(&itd->itd_list, &stream->td_list); -+ itd->stream = stream; -+ itd->urb = urb; -+ itd_init(fotg210, stream, itd); -+ } -+ -+ uframe = next_uframe & 0x07; -+ frame = next_uframe >> 3; -+ -+ itd_patch(fotg210, itd, iso_sched, packet, uframe); -+ -+ next_uframe += stream->interval; -+ next_uframe &= mod - 1; -+ packet++; -+ -+ /* link completed itds into the schedule */ -+ if (((next_uframe >> 3) != frame) -+ || packet == urb->number_of_packets) { -+ itd_link(fotg210, frame & (fotg210->periodic_size - 1), -+ itd); -+ itd = NULL; -+ } -+ } -+ stream->next_uframe = next_uframe; -+ -+ /* don't need that schedule data any more */ -+ iso_sched_free(stream, iso_sched); -+ urb->hcpriv = NULL; -+ -+ ++fotg210->isoc_count; -+ enable_periodic(fotg210); -+} -+ -+#define ISO_ERRS (FOTG210_ISOC_BUF_ERR | FOTG210_ISOC_BABBLE |\ -+ FOTG210_ISOC_XACTERR) -+ -+/* Process and recycle a completed ITD. Return true iff its urb completed, -+ * and hence its completion callback probably added things to the hardware -+ * schedule. -+ * -+ * Note that we carefully avoid recycling this descriptor until after any -+ * completion callback runs, so that it won't be reused quickly. That is, -+ * assuming (a) no more than two urbs per frame on this endpoint, and also -+ * (b) only this endpoint's completions submit URBs. It seems some silicon -+ * corrupts things if you reuse completed descriptors very quickly... -+ */ -+static bool itd_complete(struct fotg210_hcd *fotg210, struct fotg210_itd *itd) -+{ -+ struct urb *urb = itd->urb; -+ struct usb_iso_packet_descriptor *desc; -+ u32 t; -+ unsigned uframe; -+ int urb_index = -1; -+ struct fotg210_iso_stream *stream = itd->stream; -+ struct usb_device *dev; -+ bool retval = false; -+ -+ /* for each uframe with a packet */ -+ for (uframe = 0; uframe < 8; uframe++) { -+ if (likely(itd->index[uframe] == -1)) -+ continue; -+ urb_index = itd->index[uframe]; -+ desc = &urb->iso_frame_desc[urb_index]; -+ -+ t = hc32_to_cpup(fotg210, &itd->hw_transaction[uframe]); -+ itd->hw_transaction[uframe] = 0; -+ -+ /* report transfer status */ -+ if (unlikely(t & ISO_ERRS)) { -+ urb->error_count++; -+ if (t & FOTG210_ISOC_BUF_ERR) -+ desc->status = usb_pipein(urb->pipe) -+ ? -ENOSR /* hc couldn't read */ -+ : -ECOMM; /* hc couldn't write */ -+ else if (t & FOTG210_ISOC_BABBLE) -+ desc->status = -EOVERFLOW; -+ else /* (t & FOTG210_ISOC_XACTERR) */ -+ desc->status = -EPROTO; -+ -+ /* HC need not update length with this error */ -+ if (!(t & FOTG210_ISOC_BABBLE)) { -+ desc->actual_length = FOTG210_ITD_LENGTH(t); -+ urb->actual_length += desc->actual_length; -+ } -+ } else if (likely((t & FOTG210_ISOC_ACTIVE) == 0)) { -+ desc->status = 0; -+ desc->actual_length = FOTG210_ITD_LENGTH(t); -+ urb->actual_length += desc->actual_length; -+ } else { -+ /* URB was too late */ -+ desc->status = -EXDEV; -+ } -+ } -+ -+ /* handle completion now? */ -+ if (likely((urb_index + 1) != urb->number_of_packets)) -+ goto done; -+ -+ /* ASSERT: it's really the last itd for this urb -+ * list_for_each_entry (itd, &stream->td_list, itd_list) -+ * BUG_ON (itd->urb == urb); -+ */ -+ -+ /* give urb back to the driver; completion often (re)submits */ -+ dev = urb->dev; -+ fotg210_urb_done(fotg210, urb, 0); -+ retval = true; -+ urb = NULL; -+ -+ --fotg210->isoc_count; -+ disable_periodic(fotg210); -+ -+ if (unlikely(list_is_singular(&stream->td_list))) { -+ fotg210_to_hcd(fotg210)->self.bandwidth_allocated -+ -= stream->bandwidth; -+ fotg210_dbg(fotg210, -+ "deschedule devp %s ep%d%s-iso\n", -+ dev->devpath, stream->bEndpointAddress & 0x0f, -+ (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out"); -+ } -+ -+done: -+ itd->urb = NULL; -+ -+ /* Add to the end of the free list for later reuse */ -+ list_move_tail(&itd->itd_list, &stream->free_list); -+ -+ /* Recycle the iTDs when the pipeline is empty (ep no longer in use) */ -+ if (list_empty(&stream->td_list)) { -+ list_splice_tail_init(&stream->free_list, -+ &fotg210->cached_itd_list); -+ start_free_itds(fotg210); -+ } -+ -+ return retval; -+} -+ -+static int itd_submit(struct fotg210_hcd *fotg210, struct urb *urb, -+ gfp_t mem_flags) -+{ -+ int status = -EINVAL; -+ unsigned long flags; -+ struct fotg210_iso_stream *stream; -+ -+ /* Get iso_stream head */ -+ stream = iso_stream_find(fotg210, urb); -+ if (unlikely(stream == NULL)) { -+ fotg210_dbg(fotg210, "can't get iso stream\n"); -+ return -ENOMEM; -+ } -+ if (unlikely(urb->interval != stream->interval && -+ fotg210_port_speed(fotg210, 0) == -+ USB_PORT_STAT_HIGH_SPEED)) { -+ fotg210_dbg(fotg210, "can't change iso interval %d --> %d\n", -+ stream->interval, urb->interval); -+ goto done; -+ } -+ -+#ifdef FOTG210_URB_TRACE -+ fotg210_dbg(fotg210, -+ "%s %s urb %p ep%d%s len %d, %d pkts %d uframes[%p]\n", -+ __func__, urb->dev->devpath, urb, -+ usb_pipeendpoint(urb->pipe), -+ usb_pipein(urb->pipe) ? "in" : "out", -+ urb->transfer_buffer_length, -+ urb->number_of_packets, urb->interval, -+ stream); -+#endif -+ -+ /* allocate ITDs w/o locking anything */ -+ status = itd_urb_transaction(stream, fotg210, urb, mem_flags); -+ if (unlikely(status < 0)) { -+ fotg210_dbg(fotg210, "can't init itds\n"); -+ goto done; -+ } -+ -+ /* schedule ... need to lock */ -+ spin_lock_irqsave(&fotg210->lock, flags); -+ if (unlikely(!HCD_HW_ACCESSIBLE(fotg210_to_hcd(fotg210)))) { -+ status = -ESHUTDOWN; -+ goto done_not_linked; -+ } -+ status = usb_hcd_link_urb_to_ep(fotg210_to_hcd(fotg210), urb); -+ if (unlikely(status)) -+ goto done_not_linked; -+ status = iso_stream_schedule(fotg210, urb, stream); -+ if (likely(status == 0)) -+ itd_link_urb(fotg210, urb, fotg210->periodic_size << 3, stream); -+ else -+ usb_hcd_unlink_urb_from_ep(fotg210_to_hcd(fotg210), urb); -+done_not_linked: -+ spin_unlock_irqrestore(&fotg210->lock, flags); -+done: -+ return status; -+} -+ -+static inline int scan_frame_queue(struct fotg210_hcd *fotg210, unsigned frame, -+ unsigned now_frame, bool live) -+{ -+ unsigned uf; -+ bool modified; -+ union fotg210_shadow q, *q_p; -+ __hc32 type, *hw_p; -+ -+ /* scan each element in frame's queue for completions */ -+ q_p = &fotg210->pshadow[frame]; -+ hw_p = &fotg210->periodic[frame]; -+ q.ptr = q_p->ptr; -+ type = Q_NEXT_TYPE(fotg210, *hw_p); -+ modified = false; -+ -+ while (q.ptr) { -+ switch (hc32_to_cpu(fotg210, type)) { -+ case Q_TYPE_ITD: -+ /* If this ITD is still active, leave it for -+ * later processing ... check the next entry. -+ * No need to check for activity unless the -+ * frame is current. -+ */ -+ if (frame == now_frame && live) { -+ rmb(); -+ for (uf = 0; uf < 8; uf++) { -+ if (q.itd->hw_transaction[uf] & -+ ITD_ACTIVE(fotg210)) -+ break; -+ } -+ if (uf < 8) { -+ q_p = &q.itd->itd_next; -+ hw_p = &q.itd->hw_next; -+ type = Q_NEXT_TYPE(fotg210, -+ q.itd->hw_next); -+ q = *q_p; -+ break; -+ } -+ } -+ -+ /* Take finished ITDs out of the schedule -+ * and process them: recycle, maybe report -+ * URB completion. HC won't cache the -+ * pointer for much longer, if at all. -+ */ -+ *q_p = q.itd->itd_next; -+ *hw_p = q.itd->hw_next; -+ type = Q_NEXT_TYPE(fotg210, q.itd->hw_next); -+ wmb(); -+ modified = itd_complete(fotg210, q.itd); -+ q = *q_p; -+ break; -+ default: -+ fotg210_dbg(fotg210, "corrupt type %d frame %d shadow %p\n", -+ type, frame, q.ptr); -+ fallthrough; -+ case Q_TYPE_QH: -+ case Q_TYPE_FSTN: -+ /* End of the iTDs and siTDs */ -+ q.ptr = NULL; -+ break; -+ } -+ -+ /* assume completion callbacks modify the queue */ -+ if (unlikely(modified && fotg210->isoc_count > 0)) -+ return -EINVAL; -+ } -+ return 0; -+} -+ -+static void scan_isoc(struct fotg210_hcd *fotg210) -+{ -+ unsigned uf, now_frame, frame, ret; -+ unsigned fmask = fotg210->periodic_size - 1; -+ bool live; -+ -+ /* -+ * When running, scan from last scan point up to "now" -+ * else clean up by scanning everything that's left. -+ * Touches as few pages as possible: cache-friendly. -+ */ -+ if (fotg210->rh_state >= FOTG210_RH_RUNNING) { -+ uf = fotg210_read_frame_index(fotg210); -+ now_frame = (uf >> 3) & fmask; -+ live = true; -+ } else { -+ now_frame = (fotg210->next_frame - 1) & fmask; -+ live = false; -+ } -+ fotg210->now_frame = now_frame; -+ -+ frame = fotg210->next_frame; -+ for (;;) { -+ ret = 1; -+ while (ret != 0) -+ ret = scan_frame_queue(fotg210, frame, -+ now_frame, live); -+ -+ /* Stop when we have reached the current frame */ -+ if (frame == now_frame) -+ break; -+ frame = (frame + 1) & fmask; -+ } -+ fotg210->next_frame = now_frame; -+} -+ -+/* Display / Set uframe_periodic_max -+ */ -+static ssize_t uframe_periodic_max_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct fotg210_hcd *fotg210; -+ int n; -+ -+ fotg210 = hcd_to_fotg210(bus_to_hcd(dev_get_drvdata(dev))); -+ n = scnprintf(buf, PAGE_SIZE, "%d\n", fotg210->uframe_periodic_max); -+ return n; -+} -+ -+ -+static ssize_t uframe_periodic_max_store(struct device *dev, -+ struct device_attribute *attr, const char *buf, size_t count) -+{ -+ struct fotg210_hcd *fotg210; -+ unsigned uframe_periodic_max; -+ unsigned frame, uframe; -+ unsigned short allocated_max; -+ unsigned long flags; -+ ssize_t ret; -+ -+ fotg210 = hcd_to_fotg210(bus_to_hcd(dev_get_drvdata(dev))); -+ if (kstrtouint(buf, 0, &uframe_periodic_max) < 0) -+ return -EINVAL; -+ -+ if (uframe_periodic_max < 100 || uframe_periodic_max >= 125) { -+ fotg210_info(fotg210, "rejecting invalid request for uframe_periodic_max=%u\n", -+ uframe_periodic_max); -+ return -EINVAL; -+ } -+ -+ ret = -EINVAL; -+ -+ /* -+ * lock, so that our checking does not race with possible periodic -+ * bandwidth allocation through submitting new urbs. -+ */ -+ spin_lock_irqsave(&fotg210->lock, flags); -+ -+ /* -+ * for request to decrease max periodic bandwidth, we have to check -+ * every microframe in the schedule to see whether the decrease is -+ * possible. -+ */ -+ if (uframe_periodic_max < fotg210->uframe_periodic_max) { -+ allocated_max = 0; -+ -+ for (frame = 0; frame < fotg210->periodic_size; ++frame) -+ for (uframe = 0; uframe < 7; ++uframe) -+ allocated_max = max(allocated_max, -+ periodic_usecs(fotg210, frame, -+ uframe)); -+ -+ if (allocated_max > uframe_periodic_max) { -+ fotg210_info(fotg210, -+ "cannot decrease uframe_periodic_max because periodic bandwidth is already allocated (%u > %u)\n", -+ allocated_max, uframe_periodic_max); -+ goto out_unlock; -+ } -+ } -+ -+ /* increasing is always ok */ -+ -+ fotg210_info(fotg210, -+ "setting max periodic bandwidth to %u%% (== %u usec/uframe)\n", -+ 100 * uframe_periodic_max/125, uframe_periodic_max); -+ -+ if (uframe_periodic_max != 100) -+ fotg210_warn(fotg210, "max periodic bandwidth set is non-standard\n"); -+ -+ fotg210->uframe_periodic_max = uframe_periodic_max; -+ ret = count; -+ -+out_unlock: -+ spin_unlock_irqrestore(&fotg210->lock, flags); -+ return ret; -+} -+ -+static DEVICE_ATTR_RW(uframe_periodic_max); -+ -+static inline int create_sysfs_files(struct fotg210_hcd *fotg210) -+{ -+ struct device *controller = fotg210_to_hcd(fotg210)->self.controller; -+ -+ return device_create_file(controller, &dev_attr_uframe_periodic_max); -+} -+ -+static inline void remove_sysfs_files(struct fotg210_hcd *fotg210) -+{ -+ struct device *controller = fotg210_to_hcd(fotg210)->self.controller; -+ -+ device_remove_file(controller, &dev_attr_uframe_periodic_max); -+} -+/* On some systems, leaving remote wakeup enabled prevents system shutdown. -+ * The firmware seems to think that powering off is a wakeup event! -+ * This routine turns off remote wakeup and everything else, on all ports. -+ */ -+static void fotg210_turn_off_all_ports(struct fotg210_hcd *fotg210) -+{ -+ u32 __iomem *status_reg = &fotg210->regs->port_status; -+ -+ fotg210_writel(fotg210, PORT_RWC_BITS, status_reg); -+} -+ -+/* Halt HC, turn off all ports, and let the BIOS use the companion controllers. -+ * Must be called with interrupts enabled and the lock not held. -+ */ -+static void fotg210_silence_controller(struct fotg210_hcd *fotg210) -+{ -+ fotg210_halt(fotg210); -+ -+ spin_lock_irq(&fotg210->lock); -+ fotg210->rh_state = FOTG210_RH_HALTED; -+ fotg210_turn_off_all_ports(fotg210); -+ spin_unlock_irq(&fotg210->lock); -+} -+ -+/* fotg210_shutdown kick in for silicon on any bus (not just pci, etc). -+ * This forcibly disables dma and IRQs, helping kexec and other cases -+ * where the next system software may expect clean state. -+ */ -+static void fotg210_shutdown(struct usb_hcd *hcd) -+{ -+ struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); -+ -+ spin_lock_irq(&fotg210->lock); -+ fotg210->shutdown = true; -+ fotg210->rh_state = FOTG210_RH_STOPPING; -+ fotg210->enabled_hrtimer_events = 0; -+ spin_unlock_irq(&fotg210->lock); -+ -+ fotg210_silence_controller(fotg210); -+ -+ hrtimer_cancel(&fotg210->hrtimer); -+} -+ -+/* fotg210_work is called from some interrupts, timers, and so on. -+ * it calls driver completion functions, after dropping fotg210->lock. -+ */ -+static void fotg210_work(struct fotg210_hcd *fotg210) -+{ -+ /* another CPU may drop fotg210->lock during a schedule scan while -+ * it reports urb completions. this flag guards against bogus -+ * attempts at re-entrant schedule scanning. -+ */ -+ if (fotg210->scanning) { -+ fotg210->need_rescan = true; -+ return; -+ } -+ fotg210->scanning = true; -+ -+rescan: -+ fotg210->need_rescan = false; -+ if (fotg210->async_count) -+ scan_async(fotg210); -+ if (fotg210->intr_count > 0) -+ scan_intr(fotg210); -+ if (fotg210->isoc_count > 0) -+ scan_isoc(fotg210); -+ if (fotg210->need_rescan) -+ goto rescan; -+ fotg210->scanning = false; -+ -+ /* the IO watchdog guards against hardware or driver bugs that -+ * misplace IRQs, and should let us run completely without IRQs. -+ * such lossage has been observed on both VT6202 and VT8235. -+ */ -+ turn_on_io_watchdog(fotg210); -+} -+ -+/* Called when the fotg210_hcd module is removed. -+ */ -+static void fotg210_stop(struct usb_hcd *hcd) -+{ -+ struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); -+ -+ fotg210_dbg(fotg210, "stop\n"); -+ -+ /* no more interrupts ... */ -+ -+ spin_lock_irq(&fotg210->lock); -+ fotg210->enabled_hrtimer_events = 0; -+ spin_unlock_irq(&fotg210->lock); -+ -+ fotg210_quiesce(fotg210); -+ fotg210_silence_controller(fotg210); -+ fotg210_reset(fotg210); -+ -+ hrtimer_cancel(&fotg210->hrtimer); -+ remove_sysfs_files(fotg210); -+ remove_debug_files(fotg210); -+ -+ /* root hub is shut down separately (first, when possible) */ -+ spin_lock_irq(&fotg210->lock); -+ end_free_itds(fotg210); -+ spin_unlock_irq(&fotg210->lock); -+ fotg210_mem_cleanup(fotg210); -+ -+#ifdef FOTG210_STATS -+ fotg210_dbg(fotg210, "irq normal %ld err %ld iaa %ld (lost %ld)\n", -+ fotg210->stats.normal, fotg210->stats.error, -+ fotg210->stats.iaa, fotg210->stats.lost_iaa); -+ fotg210_dbg(fotg210, "complete %ld unlink %ld\n", -+ fotg210->stats.complete, fotg210->stats.unlink); -+#endif -+ -+ dbg_status(fotg210, "fotg210_stop completed", -+ fotg210_readl(fotg210, &fotg210->regs->status)); -+} -+ -+/* one-time init, only for memory state */ -+static int hcd_fotg210_init(struct usb_hcd *hcd) -+{ -+ struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); -+ u32 temp; -+ int retval; -+ u32 hcc_params; -+ struct fotg210_qh_hw *hw; -+ -+ spin_lock_init(&fotg210->lock); -+ -+ /* -+ * keep io watchdog by default, those good HCDs could turn off it later -+ */ -+ fotg210->need_io_watchdog = 1; -+ -+ hrtimer_init(&fotg210->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); -+ fotg210->hrtimer.function = fotg210_hrtimer_func; -+ fotg210->next_hrtimer_event = FOTG210_HRTIMER_NO_EVENT; -+ -+ hcc_params = fotg210_readl(fotg210, &fotg210->caps->hcc_params); -+ -+ /* -+ * by default set standard 80% (== 100 usec/uframe) max periodic -+ * bandwidth as required by USB 2.0 -+ */ -+ fotg210->uframe_periodic_max = 100; -+ -+ /* -+ * hw default: 1K periodic list heads, one per frame. -+ * periodic_size can shrink by USBCMD update if hcc_params allows. -+ */ -+ fotg210->periodic_size = DEFAULT_I_TDPS; -+ INIT_LIST_HEAD(&fotg210->intr_qh_list); -+ INIT_LIST_HEAD(&fotg210->cached_itd_list); -+ -+ if (HCC_PGM_FRAMELISTLEN(hcc_params)) { -+ /* periodic schedule size can be smaller than default */ -+ switch (FOTG210_TUNE_FLS) { -+ case 0: -+ fotg210->periodic_size = 1024; -+ break; -+ case 1: -+ fotg210->periodic_size = 512; -+ break; -+ case 2: -+ fotg210->periodic_size = 256; -+ break; -+ default: -+ BUG(); -+ } -+ } -+ retval = fotg210_mem_init(fotg210, GFP_KERNEL); -+ if (retval < 0) -+ return retval; -+ -+ /* controllers may cache some of the periodic schedule ... */ -+ fotg210->i_thresh = 2; -+ -+ /* -+ * dedicate a qh for the async ring head, since we couldn't unlink -+ * a 'real' qh without stopping the async schedule [4.8]. use it -+ * as the 'reclamation list head' too. -+ * its dummy is used in hw_alt_next of many tds, to prevent the qh -+ * from automatically advancing to the next td after short reads. -+ */ -+ fotg210->async->qh_next.qh = NULL; -+ hw = fotg210->async->hw; -+ hw->hw_next = QH_NEXT(fotg210, fotg210->async->qh_dma); -+ hw->hw_info1 = cpu_to_hc32(fotg210, QH_HEAD); -+ hw->hw_token = cpu_to_hc32(fotg210, QTD_STS_HALT); -+ hw->hw_qtd_next = FOTG210_LIST_END(fotg210); -+ fotg210->async->qh_state = QH_STATE_LINKED; -+ hw->hw_alt_next = QTD_NEXT(fotg210, fotg210->async->dummy->qtd_dma); -+ -+ /* clear interrupt enables, set irq latency */ -+ if (log2_irq_thresh < 0 || log2_irq_thresh > 6) -+ log2_irq_thresh = 0; -+ temp = 1 << (16 + log2_irq_thresh); -+ if (HCC_CANPARK(hcc_params)) { -+ /* HW default park == 3, on hardware that supports it (like -+ * NVidia and ALI silicon), maximizes throughput on the async -+ * schedule by avoiding QH fetches between transfers. -+ * -+ * With fast usb storage devices and NForce2, "park" seems to -+ * make problems: throughput reduction (!), data errors... -+ */ -+ if (park) { -+ park = min_t(unsigned, park, 3); -+ temp |= CMD_PARK; -+ temp |= park << 8; -+ } -+ fotg210_dbg(fotg210, "park %d\n", park); -+ } -+ if (HCC_PGM_FRAMELISTLEN(hcc_params)) { -+ /* periodic schedule size can be smaller than default */ -+ temp &= ~(3 << 2); -+ temp |= (FOTG210_TUNE_FLS << 2); -+ } -+ fotg210->command = temp; -+ -+ /* Accept arbitrarily long scatter-gather lists */ -+ if (!hcd->localmem_pool) -+ hcd->self.sg_tablesize = ~0; -+ return 0; -+} -+ -+/* start HC running; it's halted, hcd_fotg210_init() has been run (once) */ -+static int fotg210_run(struct usb_hcd *hcd) -+{ -+ struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); -+ u32 temp; -+ -+ hcd->uses_new_polling = 1; -+ -+ /* EHCI spec section 4.1 */ -+ -+ fotg210_writel(fotg210, fotg210->periodic_dma, -+ &fotg210->regs->frame_list); -+ fotg210_writel(fotg210, (u32)fotg210->async->qh_dma, -+ &fotg210->regs->async_next); -+ -+ /* -+ * hcc_params controls whether fotg210->regs->segment must (!!!) -+ * be used; it constrains QH/ITD/SITD and QTD locations. -+ * dma_pool consistent memory always uses segment zero. -+ * streaming mappings for I/O buffers, like dma_map_single(), -+ * can return segments above 4GB, if the device allows. -+ * -+ * NOTE: the dma mask is visible through dev->dma_mask, so -+ * drivers can pass this info along ... like NETIF_F_HIGHDMA, -+ * Scsi_Host.highmem_io, and so forth. It's readonly to all -+ * host side drivers though. -+ */ -+ fotg210_readl(fotg210, &fotg210->caps->hcc_params); -+ -+ /* -+ * Philips, Intel, and maybe others need CMD_RUN before the -+ * root hub will detect new devices (why?); NEC doesn't -+ */ -+ fotg210->command &= ~(CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET); -+ fotg210->command |= CMD_RUN; -+ fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command); -+ dbg_cmd(fotg210, "init", fotg210->command); -+ -+ /* -+ * Start, enabling full USB 2.0 functionality ... usb 1.1 devices -+ * are explicitly handed to companion controller(s), so no TT is -+ * involved with the root hub. (Except where one is integrated, -+ * and there's no companion controller unless maybe for USB OTG.) -+ * -+ * Turning on the CF flag will transfer ownership of all ports -+ * from the companions to the EHCI controller. If any of the -+ * companions are in the middle of a port reset at the time, it -+ * could cause trouble. Write-locking ehci_cf_port_reset_rwsem -+ * guarantees that no resets are in progress. After we set CF, -+ * a short delay lets the hardware catch up; new resets shouldn't -+ * be started before the port switching actions could complete. -+ */ -+ down_write(&ehci_cf_port_reset_rwsem); -+ fotg210->rh_state = FOTG210_RH_RUNNING; -+ /* unblock posted writes */ -+ fotg210_readl(fotg210, &fotg210->regs->command); -+ usleep_range(5000, 10000); -+ up_write(&ehci_cf_port_reset_rwsem); -+ fotg210->last_periodic_enable = ktime_get_real(); -+ -+ temp = HC_VERSION(fotg210, -+ fotg210_readl(fotg210, &fotg210->caps->hc_capbase)); -+ fotg210_info(fotg210, -+ "USB %x.%x started, EHCI %x.%02x\n", -+ ((fotg210->sbrn & 0xf0) >> 4), (fotg210->sbrn & 0x0f), -+ temp >> 8, temp & 0xff); -+ -+ fotg210_writel(fotg210, INTR_MASK, -+ &fotg210->regs->intr_enable); /* Turn On Interrupts */ -+ -+ /* GRR this is run-once init(), being done every time the HC starts. -+ * So long as they're part of class devices, we can't do it init() -+ * since the class device isn't created that early. -+ */ -+ create_debug_files(fotg210); -+ create_sysfs_files(fotg210); -+ -+ return 0; -+} -+ -+static int fotg210_setup(struct usb_hcd *hcd) -+{ -+ struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); -+ int retval; -+ -+ fotg210->regs = (void __iomem *)fotg210->caps + -+ HC_LENGTH(fotg210, -+ fotg210_readl(fotg210, &fotg210->caps->hc_capbase)); -+ dbg_hcs_params(fotg210, "reset"); -+ dbg_hcc_params(fotg210, "reset"); -+ -+ /* cache this readonly data; minimize chip reads */ -+ fotg210->hcs_params = fotg210_readl(fotg210, -+ &fotg210->caps->hcs_params); -+ -+ fotg210->sbrn = HCD_USB2; -+ -+ /* data structure init */ -+ retval = hcd_fotg210_init(hcd); -+ if (retval) -+ return retval; -+ -+ retval = fotg210_halt(fotg210); -+ if (retval) -+ return retval; -+ -+ fotg210_reset(fotg210); -+ -+ return 0; -+} -+ -+static irqreturn_t fotg210_irq(struct usb_hcd *hcd) -+{ -+ struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); -+ u32 status, masked_status, pcd_status = 0, cmd; -+ int bh; -+ -+ spin_lock(&fotg210->lock); -+ -+ status = fotg210_readl(fotg210, &fotg210->regs->status); -+ -+ /* e.g. cardbus physical eject */ -+ if (status == ~(u32) 0) { -+ fotg210_dbg(fotg210, "device removed\n"); -+ goto dead; -+ } -+ -+ /* -+ * We don't use STS_FLR, but some controllers don't like it to -+ * remain on, so mask it out along with the other status bits. -+ */ -+ masked_status = status & (INTR_MASK | STS_FLR); -+ -+ /* Shared IRQ? */ -+ if (!masked_status || -+ unlikely(fotg210->rh_state == FOTG210_RH_HALTED)) { -+ spin_unlock(&fotg210->lock); -+ return IRQ_NONE; -+ } -+ -+ /* clear (just) interrupts */ -+ fotg210_writel(fotg210, masked_status, &fotg210->regs->status); -+ cmd = fotg210_readl(fotg210, &fotg210->regs->command); -+ bh = 0; -+ -+ /* unrequested/ignored: Frame List Rollover */ -+ dbg_status(fotg210, "irq", status); -+ -+ /* INT, ERR, and IAA interrupt rates can be throttled */ -+ -+ /* normal [4.15.1.2] or error [4.15.1.1] completion */ -+ if (likely((status & (STS_INT|STS_ERR)) != 0)) { -+ if (likely((status & STS_ERR) == 0)) -+ INCR(fotg210->stats.normal); -+ else -+ INCR(fotg210->stats.error); -+ bh = 1; -+ } -+ -+ /* complete the unlinking of some qh [4.15.2.3] */ -+ if (status & STS_IAA) { -+ -+ /* Turn off the IAA watchdog */ -+ fotg210->enabled_hrtimer_events &= -+ ~BIT(FOTG210_HRTIMER_IAA_WATCHDOG); -+ -+ /* -+ * Mild optimization: Allow another IAAD to reset the -+ * hrtimer, if one occurs before the next expiration. -+ * In theory we could always cancel the hrtimer, but -+ * tests show that about half the time it will be reset -+ * for some other event anyway. -+ */ -+ if (fotg210->next_hrtimer_event == FOTG210_HRTIMER_IAA_WATCHDOG) -+ ++fotg210->next_hrtimer_event; -+ -+ /* guard against (alleged) silicon errata */ -+ if (cmd & CMD_IAAD) -+ fotg210_dbg(fotg210, "IAA with IAAD still set?\n"); -+ if (fotg210->async_iaa) { -+ INCR(fotg210->stats.iaa); -+ end_unlink_async(fotg210); -+ } else -+ fotg210_dbg(fotg210, "IAA with nothing unlinked?\n"); -+ } -+ -+ /* remote wakeup [4.3.1] */ -+ if (status & STS_PCD) { -+ int pstatus; -+ u32 __iomem *status_reg = &fotg210->regs->port_status; -+ -+ /* kick root hub later */ -+ pcd_status = status; -+ -+ /* resume root hub? */ -+ if (fotg210->rh_state == FOTG210_RH_SUSPENDED) -+ usb_hcd_resume_root_hub(hcd); -+ -+ pstatus = fotg210_readl(fotg210, status_reg); -+ -+ if (test_bit(0, &fotg210->suspended_ports) && -+ ((pstatus & PORT_RESUME) || -+ !(pstatus & PORT_SUSPEND)) && -+ (pstatus & PORT_PE) && -+ fotg210->reset_done[0] == 0) { -+ -+ /* start 20 msec resume signaling from this port, -+ * and make hub_wq collect PORT_STAT_C_SUSPEND to -+ * stop that signaling. Use 5 ms extra for safety, -+ * like usb_port_resume() does. -+ */ -+ fotg210->reset_done[0] = jiffies + msecs_to_jiffies(25); -+ set_bit(0, &fotg210->resuming_ports); -+ fotg210_dbg(fotg210, "port 1 remote wakeup\n"); -+ mod_timer(&hcd->rh_timer, fotg210->reset_done[0]); -+ } -+ } -+ -+ /* PCI errors [4.15.2.4] */ -+ if (unlikely((status & STS_FATAL) != 0)) { -+ fotg210_err(fotg210, "fatal error\n"); -+ dbg_cmd(fotg210, "fatal", cmd); -+ dbg_status(fotg210, "fatal", status); -+dead: -+ usb_hc_died(hcd); -+ -+ /* Don't let the controller do anything more */ -+ fotg210->shutdown = true; -+ fotg210->rh_state = FOTG210_RH_STOPPING; -+ fotg210->command &= ~(CMD_RUN | CMD_ASE | CMD_PSE); -+ fotg210_writel(fotg210, fotg210->command, -+ &fotg210->regs->command); -+ fotg210_writel(fotg210, 0, &fotg210->regs->intr_enable); -+ fotg210_handle_controller_death(fotg210); -+ -+ /* Handle completions when the controller stops */ -+ bh = 0; -+ } -+ -+ if (bh) -+ fotg210_work(fotg210); -+ spin_unlock(&fotg210->lock); -+ if (pcd_status) -+ usb_hcd_poll_rh_status(hcd); -+ return IRQ_HANDLED; -+} -+ -+/* non-error returns are a promise to giveback() the urb later -+ * we drop ownership so next owner (or urb unlink) can get it -+ * -+ * urb + dev is in hcd.self.controller.urb_list -+ * we're queueing TDs onto software and hardware lists -+ * -+ * hcd-specific init for hcpriv hasn't been done yet -+ * -+ * NOTE: control, bulk, and interrupt share the same code to append TDs -+ * to a (possibly active) QH, and the same QH scanning code. -+ */ -+static int fotg210_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, -+ gfp_t mem_flags) -+{ -+ struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); -+ struct list_head qtd_list; -+ -+ INIT_LIST_HEAD(&qtd_list); -+ -+ switch (usb_pipetype(urb->pipe)) { -+ case PIPE_CONTROL: -+ /* qh_completions() code doesn't handle all the fault cases -+ * in multi-TD control transfers. Even 1KB is rare anyway. -+ */ -+ if (urb->transfer_buffer_length > (16 * 1024)) -+ return -EMSGSIZE; -+ fallthrough; -+ /* case PIPE_BULK: */ -+ default: -+ if (!qh_urb_transaction(fotg210, urb, &qtd_list, mem_flags)) -+ return -ENOMEM; -+ return submit_async(fotg210, urb, &qtd_list, mem_flags); -+ -+ case PIPE_INTERRUPT: -+ if (!qh_urb_transaction(fotg210, urb, &qtd_list, mem_flags)) -+ return -ENOMEM; -+ return intr_submit(fotg210, urb, &qtd_list, mem_flags); -+ -+ case PIPE_ISOCHRONOUS: -+ return itd_submit(fotg210, urb, mem_flags); -+ } -+} -+ -+/* remove from hardware lists -+ * completions normally happen asynchronously -+ */ -+ -+static int fotg210_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) -+{ -+ struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); -+ struct fotg210_qh *qh; -+ unsigned long flags; -+ int rc; -+ -+ spin_lock_irqsave(&fotg210->lock, flags); -+ rc = usb_hcd_check_unlink_urb(hcd, urb, status); -+ if (rc) -+ goto done; -+ -+ switch (usb_pipetype(urb->pipe)) { -+ /* case PIPE_CONTROL: */ -+ /* case PIPE_BULK:*/ -+ default: -+ qh = (struct fotg210_qh *) urb->hcpriv; -+ if (!qh) -+ break; -+ switch (qh->qh_state) { -+ case QH_STATE_LINKED: -+ case QH_STATE_COMPLETING: -+ start_unlink_async(fotg210, qh); -+ break; -+ case QH_STATE_UNLINK: -+ case QH_STATE_UNLINK_WAIT: -+ /* already started */ -+ break; -+ case QH_STATE_IDLE: -+ /* QH might be waiting for a Clear-TT-Buffer */ -+ qh_completions(fotg210, qh); -+ break; -+ } -+ break; -+ -+ case PIPE_INTERRUPT: -+ qh = (struct fotg210_qh *) urb->hcpriv; -+ if (!qh) -+ break; -+ switch (qh->qh_state) { -+ case QH_STATE_LINKED: -+ case QH_STATE_COMPLETING: -+ start_unlink_intr(fotg210, qh); -+ break; -+ case QH_STATE_IDLE: -+ qh_completions(fotg210, qh); -+ break; -+ default: -+ fotg210_dbg(fotg210, "bogus qh %p state %d\n", -+ qh, qh->qh_state); -+ goto done; -+ } -+ break; -+ -+ case PIPE_ISOCHRONOUS: -+ /* itd... */ -+ -+ /* wait till next completion, do it then. */ -+ /* completion irqs can wait up to 1024 msec, */ -+ break; -+ } -+done: -+ spin_unlock_irqrestore(&fotg210->lock, flags); -+ return rc; -+} -+ -+/* bulk qh holds the data toggle */ -+ -+static void fotg210_endpoint_disable(struct usb_hcd *hcd, -+ struct usb_host_endpoint *ep) -+{ -+ struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); -+ unsigned long flags; -+ struct fotg210_qh *qh, *tmp; -+ -+ /* ASSERT: any requests/urbs are being unlinked */ -+ /* ASSERT: nobody can be submitting urbs for this any more */ -+ -+rescan: -+ spin_lock_irqsave(&fotg210->lock, flags); -+ qh = ep->hcpriv; -+ if (!qh) -+ goto done; -+ -+ /* endpoints can be iso streams. for now, we don't -+ * accelerate iso completions ... so spin a while. -+ */ -+ if (qh->hw == NULL) { -+ struct fotg210_iso_stream *stream = ep->hcpriv; -+ -+ if (!list_empty(&stream->td_list)) -+ goto idle_timeout; -+ -+ /* BUG_ON(!list_empty(&stream->free_list)); */ -+ kfree(stream); -+ goto done; -+ } -+ -+ if (fotg210->rh_state < FOTG210_RH_RUNNING) -+ qh->qh_state = QH_STATE_IDLE; -+ switch (qh->qh_state) { -+ case QH_STATE_LINKED: -+ case QH_STATE_COMPLETING: -+ for (tmp = fotg210->async->qh_next.qh; -+ tmp && tmp != qh; -+ tmp = tmp->qh_next.qh) -+ continue; -+ /* periodic qh self-unlinks on empty, and a COMPLETING qh -+ * may already be unlinked. -+ */ -+ if (tmp) -+ start_unlink_async(fotg210, qh); -+ fallthrough; -+ case QH_STATE_UNLINK: /* wait for hw to finish? */ -+ case QH_STATE_UNLINK_WAIT: -+idle_timeout: -+ spin_unlock_irqrestore(&fotg210->lock, flags); -+ schedule_timeout_uninterruptible(1); -+ goto rescan; -+ case QH_STATE_IDLE: /* fully unlinked */ -+ if (qh->clearing_tt) -+ goto idle_timeout; -+ if (list_empty(&qh->qtd_list)) { -+ qh_destroy(fotg210, qh); -+ break; -+ } -+ fallthrough; -+ default: -+ /* caller was supposed to have unlinked any requests; -+ * that's not our job. just leak this memory. -+ */ -+ fotg210_err(fotg210, "qh %p (#%02x) state %d%s\n", -+ qh, ep->desc.bEndpointAddress, qh->qh_state, -+ list_empty(&qh->qtd_list) ? "" : "(has tds)"); -+ break; -+ } -+done: -+ ep->hcpriv = NULL; -+ spin_unlock_irqrestore(&fotg210->lock, flags); -+} -+ -+static void fotg210_endpoint_reset(struct usb_hcd *hcd, -+ struct usb_host_endpoint *ep) -+{ -+ struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); -+ struct fotg210_qh *qh; -+ int eptype = usb_endpoint_type(&ep->desc); -+ int epnum = usb_endpoint_num(&ep->desc); -+ int is_out = usb_endpoint_dir_out(&ep->desc); -+ unsigned long flags; -+ -+ if (eptype != USB_ENDPOINT_XFER_BULK && eptype != USB_ENDPOINT_XFER_INT) -+ return; -+ -+ spin_lock_irqsave(&fotg210->lock, flags); -+ qh = ep->hcpriv; -+ -+ /* For Bulk and Interrupt endpoints we maintain the toggle state -+ * in the hardware; the toggle bits in udev aren't used at all. -+ * When an endpoint is reset by usb_clear_halt() we must reset -+ * the toggle bit in the QH. -+ */ -+ if (qh) { -+ usb_settoggle(qh->dev, epnum, is_out, 0); -+ if (!list_empty(&qh->qtd_list)) { -+ WARN_ONCE(1, "clear_halt for a busy endpoint\n"); -+ } else if (qh->qh_state == QH_STATE_LINKED || -+ qh->qh_state == QH_STATE_COMPLETING) { -+ -+ /* The toggle value in the QH can't be updated -+ * while the QH is active. Unlink it now; -+ * re-linking will call qh_refresh(). -+ */ -+ if (eptype == USB_ENDPOINT_XFER_BULK) -+ start_unlink_async(fotg210, qh); -+ else -+ start_unlink_intr(fotg210, qh); -+ } -+ } -+ spin_unlock_irqrestore(&fotg210->lock, flags); -+} -+ -+static int fotg210_get_frame(struct usb_hcd *hcd) -+{ -+ struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); -+ -+ return (fotg210_read_frame_index(fotg210) >> 3) % -+ fotg210->periodic_size; -+} -+ -+/* The EHCI in ChipIdea HDRC cannot be a separate module or device, -+ * because its registers (and irq) are shared between host/gadget/otg -+ * functions and in order to facilitate role switching we cannot -+ * give the fotg210 driver exclusive access to those. -+ */ -+MODULE_DESCRIPTION(DRIVER_DESC); -+MODULE_AUTHOR(DRIVER_AUTHOR); -+MODULE_LICENSE("GPL"); -+ -+static const struct hc_driver fotg210_fotg210_hc_driver = { -+ .description = hcd_name, -+ .product_desc = "Faraday USB2.0 Host Controller", -+ .hcd_priv_size = sizeof(struct fotg210_hcd), -+ -+ /* -+ * generic hardware linkage -+ */ -+ .irq = fotg210_irq, -+ .flags = HCD_MEMORY | HCD_DMA | HCD_USB2, -+ -+ /* -+ * basic lifecycle operations -+ */ -+ .reset = hcd_fotg210_init, -+ .start = fotg210_run, -+ .stop = fotg210_stop, -+ .shutdown = fotg210_shutdown, -+ -+ /* -+ * managing i/o requests and associated device resources -+ */ -+ .urb_enqueue = fotg210_urb_enqueue, -+ .urb_dequeue = fotg210_urb_dequeue, -+ .endpoint_disable = fotg210_endpoint_disable, -+ .endpoint_reset = fotg210_endpoint_reset, -+ -+ /* -+ * scheduling support -+ */ -+ .get_frame_number = fotg210_get_frame, -+ -+ /* -+ * root hub support -+ */ -+ .hub_status_data = fotg210_hub_status_data, -+ .hub_control = fotg210_hub_control, -+ .bus_suspend = fotg210_bus_suspend, -+ .bus_resume = fotg210_bus_resume, -+ -+ .relinquish_port = fotg210_relinquish_port, -+ .port_handed_over = fotg210_port_handed_over, -+ -+ .clear_tt_buffer_complete = fotg210_clear_tt_buffer_complete, -+}; -+ -+static void fotg210_init(struct fotg210_hcd *fotg210) -+{ -+ u32 value; -+ -+ iowrite32(GMIR_MDEV_INT | GMIR_MOTG_INT | GMIR_INT_POLARITY, -+ &fotg210->regs->gmir); -+ -+ value = ioread32(&fotg210->regs->otgcsr); -+ value &= ~OTGCSR_A_BUS_DROP; -+ value |= OTGCSR_A_BUS_REQ; -+ iowrite32(value, &fotg210->regs->otgcsr); -+} -+ -+/* -+ * fotg210_hcd_probe - initialize faraday FOTG210 HCDs -+ * -+ * Allocates basic resources for this USB host controller, and -+ * then invokes the start() method for the HCD associated with it -+ * through the hotplug entry's driver_data. -+ */ -+static int fotg210_hcd_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct usb_hcd *hcd; -+ struct resource *res; -+ int irq; -+ int retval; -+ struct fotg210_hcd *fotg210; -+ -+ if (usb_disabled()) -+ return -ENODEV; -+ -+ pdev->dev.power.power_state = PMSG_ON; -+ -+ irq = platform_get_irq(pdev, 0); -+ if (irq < 0) -+ return irq; -+ -+ hcd = usb_create_hcd(&fotg210_fotg210_hc_driver, dev, -+ dev_name(dev)); -+ if (!hcd) { -+ dev_err(dev, "failed to create hcd\n"); -+ retval = -ENOMEM; -+ goto fail_create_hcd; -+ } -+ -+ hcd->has_tt = 1; -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ hcd->regs = devm_ioremap_resource(&pdev->dev, res); -+ if (IS_ERR(hcd->regs)) { -+ retval = PTR_ERR(hcd->regs); -+ goto failed_put_hcd; -+ } -+ -+ hcd->rsrc_start = res->start; -+ hcd->rsrc_len = resource_size(res); -+ -+ fotg210 = hcd_to_fotg210(hcd); -+ -+ fotg210->caps = hcd->regs; -+ -+ /* It's OK not to supply this clock */ -+ fotg210->pclk = clk_get(dev, "PCLK"); -+ if (!IS_ERR(fotg210->pclk)) { -+ retval = clk_prepare_enable(fotg210->pclk); -+ if (retval) { -+ dev_err(dev, "failed to enable PCLK\n"); -+ goto failed_put_hcd; -+ } -+ } else if (PTR_ERR(fotg210->pclk) == -EPROBE_DEFER) { -+ /* -+ * Percolate deferrals, for anything else, -+ * just live without the clocking. -+ */ -+ retval = PTR_ERR(fotg210->pclk); -+ goto failed_dis_clk; -+ } -+ -+ retval = fotg210_setup(hcd); -+ if (retval) -+ goto failed_dis_clk; -+ -+ fotg210_init(fotg210); -+ -+ retval = usb_add_hcd(hcd, irq, IRQF_SHARED); -+ if (retval) { -+ dev_err(dev, "failed to add hcd with err %d\n", retval); -+ goto failed_dis_clk; -+ } -+ device_wakeup_enable(hcd->self.controller); -+ platform_set_drvdata(pdev, hcd); -+ -+ return retval; -+ -+failed_dis_clk: -+ if (!IS_ERR(fotg210->pclk)) { -+ clk_disable_unprepare(fotg210->pclk); -+ clk_put(fotg210->pclk); -+ } -+failed_put_hcd: -+ usb_put_hcd(hcd); -+fail_create_hcd: -+ dev_err(dev, "init %s fail, %d\n", dev_name(dev), retval); -+ return retval; -+} -+ -+/* -+ * fotg210_hcd_remove - shutdown processing for EHCI HCDs -+ * @dev: USB Host Controller being removed -+ * -+ */ -+static int fotg210_hcd_remove(struct platform_device *pdev) -+{ -+ struct usb_hcd *hcd = platform_get_drvdata(pdev); -+ struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); -+ -+ if (!IS_ERR(fotg210->pclk)) { -+ clk_disable_unprepare(fotg210->pclk); -+ clk_put(fotg210->pclk); -+ } -+ -+ usb_remove_hcd(hcd); -+ usb_put_hcd(hcd); -+ -+ return 0; -+} -+ -+#ifdef CONFIG_OF -+static const struct of_device_id fotg210_of_match[] = { -+ { .compatible = "faraday,fotg210" }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, fotg210_of_match); -+#endif -+ -+static struct platform_driver fotg210_hcd_driver = { -+ .driver = { -+ .name = "fotg210-hcd", -+ .of_match_table = of_match_ptr(fotg210_of_match), -+ }, -+ .probe = fotg210_hcd_probe, -+ .remove = fotg210_hcd_remove, -+}; -+ -+static int __init fotg210_hcd_init(void) -+{ -+ int retval = 0; -+ -+ if (usb_disabled()) -+ return -ENODEV; -+ -+ set_bit(USB_EHCI_LOADED, &usb_hcds_loaded); -+ if (test_bit(USB_UHCI_LOADED, &usb_hcds_loaded) || -+ test_bit(USB_OHCI_LOADED, &usb_hcds_loaded)) -+ pr_warn("Warning! fotg210_hcd should always be loaded before uhci_hcd and ohci_hcd, not after\n"); -+ -+ pr_debug("%s: block sizes: qh %zd qtd %zd itd %zd\n", -+ hcd_name, sizeof(struct fotg210_qh), -+ sizeof(struct fotg210_qtd), -+ sizeof(struct fotg210_itd)); -+ -+ fotg210_debug_root = debugfs_create_dir("fotg210", usb_debug_root); -+ -+ retval = platform_driver_register(&fotg210_hcd_driver); -+ if (retval < 0) -+ goto clean; -+ return retval; -+ -+clean: -+ debugfs_remove(fotg210_debug_root); -+ fotg210_debug_root = NULL; -+ -+ clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded); -+ return retval; -+} -+module_init(fotg210_hcd_init); -+ -+static void __exit fotg210_hcd_cleanup(void) -+{ -+ platform_driver_unregister(&fotg210_hcd_driver); -+ debugfs_remove(fotg210_debug_root); -+ clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded); -+} -+module_exit(fotg210_hcd_cleanup); ---- a/drivers/usb/gadget/udc/fotg210-udc.c -+++ /dev/null -@@ -1,1239 +0,0 @@ --// SPDX-License-Identifier: GPL-2.0 --/* -- * FOTG210 UDC Driver supports Bulk transfer so far -- * -- * Copyright (C) 2013 Faraday Technology Corporation -- * -- * Author : Yuan-Hsin Chen -- */ -- --#include --#include --#include --#include --#include --#include --#include --#include -- --#include "fotg210.h" -- --#define DRIVER_DESC "FOTG210 USB Device Controller Driver" --#define DRIVER_VERSION "30-April-2013" -- --static const char udc_name[] = "fotg210_udc"; --static const char * const fotg210_ep_name[] = { -- "ep0", "ep1", "ep2", "ep3", "ep4"}; -- --static void fotg210_disable_fifo_int(struct fotg210_ep *ep) --{ -- u32 value = ioread32(ep->fotg210->reg + FOTG210_DMISGR1); -- -- if (ep->dir_in) -- value |= DMISGR1_MF_IN_INT(ep->epnum - 1); -- else -- value |= DMISGR1_MF_OUTSPK_INT(ep->epnum - 1); -- iowrite32(value, ep->fotg210->reg + FOTG210_DMISGR1); --} -- --static void fotg210_enable_fifo_int(struct fotg210_ep *ep) --{ -- u32 value = ioread32(ep->fotg210->reg + FOTG210_DMISGR1); -- -- if (ep->dir_in) -- value &= ~DMISGR1_MF_IN_INT(ep->epnum - 1); -- else -- value &= ~DMISGR1_MF_OUTSPK_INT(ep->epnum - 1); -- iowrite32(value, ep->fotg210->reg + FOTG210_DMISGR1); --} -- --static void fotg210_set_cxdone(struct fotg210_udc *fotg210) --{ -- u32 value = ioread32(fotg210->reg + FOTG210_DCFESR); -- -- value |= DCFESR_CX_DONE; -- iowrite32(value, fotg210->reg + FOTG210_DCFESR); --} -- --static void fotg210_done(struct fotg210_ep *ep, struct fotg210_request *req, -- int status) --{ -- list_del_init(&req->queue); -- -- /* don't modify queue heads during completion callback */ -- if (ep->fotg210->gadget.speed == USB_SPEED_UNKNOWN) -- req->req.status = -ESHUTDOWN; -- else -- req->req.status = status; -- -- spin_unlock(&ep->fotg210->lock); -- usb_gadget_giveback_request(&ep->ep, &req->req); -- spin_lock(&ep->fotg210->lock); -- -- if (ep->epnum) { -- if (list_empty(&ep->queue)) -- fotg210_disable_fifo_int(ep); -- } else { -- fotg210_set_cxdone(ep->fotg210); -- } --} -- --static void fotg210_fifo_ep_mapping(struct fotg210_ep *ep, u32 epnum, -- u32 dir_in) --{ -- struct fotg210_udc *fotg210 = ep->fotg210; -- u32 val; -- -- /* Driver should map an ep to a fifo and then map the fifo -- * to the ep. What a brain-damaged design! -- */ -- -- /* map a fifo to an ep */ -- val = ioread32(fotg210->reg + FOTG210_EPMAP); -- val &= ~EPMAP_FIFONOMSK(epnum, dir_in); -- val |= EPMAP_FIFONO(epnum, dir_in); -- iowrite32(val, fotg210->reg + FOTG210_EPMAP); -- -- /* map the ep to the fifo */ -- val = ioread32(fotg210->reg + FOTG210_FIFOMAP); -- val &= ~FIFOMAP_EPNOMSK(epnum); -- val |= FIFOMAP_EPNO(epnum); -- iowrite32(val, fotg210->reg + FOTG210_FIFOMAP); -- -- /* enable fifo */ -- val = ioread32(fotg210->reg + FOTG210_FIFOCF); -- val |= FIFOCF_FIFO_EN(epnum - 1); -- iowrite32(val, fotg210->reg + FOTG210_FIFOCF); --} -- --static void fotg210_set_fifo_dir(struct fotg210_ep *ep, u32 epnum, u32 dir_in) --{ -- struct fotg210_udc *fotg210 = ep->fotg210; -- u32 val; -- -- val = ioread32(fotg210->reg + FOTG210_FIFOMAP); -- val |= (dir_in ? FIFOMAP_DIRIN(epnum - 1) : FIFOMAP_DIROUT(epnum - 1)); -- iowrite32(val, fotg210->reg + FOTG210_FIFOMAP); --} -- --static void fotg210_set_tfrtype(struct fotg210_ep *ep, u32 epnum, u32 type) --{ -- struct fotg210_udc *fotg210 = ep->fotg210; -- u32 val; -- -- val = ioread32(fotg210->reg + FOTG210_FIFOCF); -- val |= FIFOCF_TYPE(type, epnum - 1); -- iowrite32(val, fotg210->reg + FOTG210_FIFOCF); --} -- --static void fotg210_set_mps(struct fotg210_ep *ep, u32 epnum, u32 mps, -- u32 dir_in) --{ -- struct fotg210_udc *fotg210 = ep->fotg210; -- u32 val; -- u32 offset = dir_in ? FOTG210_INEPMPSR(epnum) : -- FOTG210_OUTEPMPSR(epnum); -- -- val = ioread32(fotg210->reg + offset); -- val |= INOUTEPMPSR_MPS(mps); -- iowrite32(val, fotg210->reg + offset); --} -- --static int fotg210_config_ep(struct fotg210_ep *ep, -- const struct usb_endpoint_descriptor *desc) --{ -- struct fotg210_udc *fotg210 = ep->fotg210; -- -- fotg210_set_fifo_dir(ep, ep->epnum, ep->dir_in); -- fotg210_set_tfrtype(ep, ep->epnum, ep->type); -- fotg210_set_mps(ep, ep->epnum, ep->ep.maxpacket, ep->dir_in); -- fotg210_fifo_ep_mapping(ep, ep->epnum, ep->dir_in); -- -- fotg210->ep[ep->epnum] = ep; -- -- return 0; --} -- --static int fotg210_ep_enable(struct usb_ep *_ep, -- const struct usb_endpoint_descriptor *desc) --{ -- struct fotg210_ep *ep; -- -- ep = container_of(_ep, struct fotg210_ep, ep); -- -- ep->desc = desc; -- ep->epnum = usb_endpoint_num(desc); -- ep->type = usb_endpoint_type(desc); -- ep->dir_in = usb_endpoint_dir_in(desc); -- ep->ep.maxpacket = usb_endpoint_maxp(desc); -- -- return fotg210_config_ep(ep, desc); --} -- --static void fotg210_reset_tseq(struct fotg210_udc *fotg210, u8 epnum) --{ -- struct fotg210_ep *ep = fotg210->ep[epnum]; -- u32 value; -- void __iomem *reg; -- -- reg = (ep->dir_in) ? -- fotg210->reg + FOTG210_INEPMPSR(epnum) : -- fotg210->reg + FOTG210_OUTEPMPSR(epnum); -- -- /* Note: Driver needs to set and clear INOUTEPMPSR_RESET_TSEQ -- * bit. Controller wouldn't clear this bit. WTF!!! -- */ -- -- value = ioread32(reg); -- value |= INOUTEPMPSR_RESET_TSEQ; -- iowrite32(value, reg); -- -- value = ioread32(reg); -- value &= ~INOUTEPMPSR_RESET_TSEQ; -- iowrite32(value, reg); --} -- --static int fotg210_ep_release(struct fotg210_ep *ep) --{ -- if (!ep->epnum) -- return 0; -- ep->epnum = 0; -- ep->stall = 0; -- ep->wedged = 0; -- -- fotg210_reset_tseq(ep->fotg210, ep->epnum); -- -- return 0; --} -- --static int fotg210_ep_disable(struct usb_ep *_ep) --{ -- struct fotg210_ep *ep; -- struct fotg210_request *req; -- unsigned long flags; -- -- BUG_ON(!_ep); -- -- ep = container_of(_ep, struct fotg210_ep, ep); -- -- while (!list_empty(&ep->queue)) { -- req = list_entry(ep->queue.next, -- struct fotg210_request, queue); -- spin_lock_irqsave(&ep->fotg210->lock, flags); -- fotg210_done(ep, req, -ECONNRESET); -- spin_unlock_irqrestore(&ep->fotg210->lock, flags); -- } -- -- return fotg210_ep_release(ep); --} -- --static struct usb_request *fotg210_ep_alloc_request(struct usb_ep *_ep, -- gfp_t gfp_flags) --{ -- struct fotg210_request *req; -- -- req = kzalloc(sizeof(struct fotg210_request), gfp_flags); -- if (!req) -- return NULL; -- -- INIT_LIST_HEAD(&req->queue); -- -- return &req->req; --} -- --static void fotg210_ep_free_request(struct usb_ep *_ep, -- struct usb_request *_req) --{ -- struct fotg210_request *req; -- -- req = container_of(_req, struct fotg210_request, req); -- kfree(req); --} -- --static void fotg210_enable_dma(struct fotg210_ep *ep, -- dma_addr_t d, u32 len) --{ -- u32 value; -- struct fotg210_udc *fotg210 = ep->fotg210; -- -- /* set transfer length and direction */ -- value = ioread32(fotg210->reg + FOTG210_DMACPSR1); -- value &= ~(DMACPSR1_DMA_LEN(0xFFFF) | DMACPSR1_DMA_TYPE(1)); -- value |= DMACPSR1_DMA_LEN(len) | DMACPSR1_DMA_TYPE(ep->dir_in); -- iowrite32(value, fotg210->reg + FOTG210_DMACPSR1); -- -- /* set device DMA target FIFO number */ -- value = ioread32(fotg210->reg + FOTG210_DMATFNR); -- if (ep->epnum) -- value |= DMATFNR_ACC_FN(ep->epnum - 1); -- else -- value |= DMATFNR_ACC_CXF; -- iowrite32(value, fotg210->reg + FOTG210_DMATFNR); -- -- /* set DMA memory address */ -- iowrite32(d, fotg210->reg + FOTG210_DMACPSR2); -- -- /* enable MDMA_EROR and MDMA_CMPLT interrupt */ -- value = ioread32(fotg210->reg + FOTG210_DMISGR2); -- value &= ~(DMISGR2_MDMA_CMPLT | DMISGR2_MDMA_ERROR); -- iowrite32(value, fotg210->reg + FOTG210_DMISGR2); -- -- /* start DMA */ -- value = ioread32(fotg210->reg + FOTG210_DMACPSR1); -- value |= DMACPSR1_DMA_START; -- iowrite32(value, fotg210->reg + FOTG210_DMACPSR1); --} -- --static void fotg210_disable_dma(struct fotg210_ep *ep) --{ -- iowrite32(DMATFNR_DISDMA, ep->fotg210->reg + FOTG210_DMATFNR); --} -- --static void fotg210_wait_dma_done(struct fotg210_ep *ep) --{ -- u32 value; -- -- do { -- value = ioread32(ep->fotg210->reg + FOTG210_DISGR2); -- if ((value & DISGR2_USBRST_INT) || -- (value & DISGR2_DMA_ERROR)) -- goto dma_reset; -- } while (!(value & DISGR2_DMA_CMPLT)); -- -- value &= ~DISGR2_DMA_CMPLT; -- iowrite32(value, ep->fotg210->reg + FOTG210_DISGR2); -- return; -- --dma_reset: -- value = ioread32(ep->fotg210->reg + FOTG210_DMACPSR1); -- value |= DMACPSR1_DMA_ABORT; -- iowrite32(value, ep->fotg210->reg + FOTG210_DMACPSR1); -- -- /* reset fifo */ -- if (ep->epnum) { -- value = ioread32(ep->fotg210->reg + -- FOTG210_FIBCR(ep->epnum - 1)); -- value |= FIBCR_FFRST; -- iowrite32(value, ep->fotg210->reg + -- FOTG210_FIBCR(ep->epnum - 1)); -- } else { -- value = ioread32(ep->fotg210->reg + FOTG210_DCFESR); -- value |= DCFESR_CX_CLR; -- iowrite32(value, ep->fotg210->reg + FOTG210_DCFESR); -- } --} -- --static void fotg210_start_dma(struct fotg210_ep *ep, -- struct fotg210_request *req) --{ -- struct device *dev = &ep->fotg210->gadget.dev; -- dma_addr_t d; -- u8 *buffer; -- u32 length; -- -- if (ep->epnum) { -- if (ep->dir_in) { -- buffer = req->req.buf; -- length = req->req.length; -- } else { -- buffer = req->req.buf + req->req.actual; -- length = ioread32(ep->fotg210->reg + -- FOTG210_FIBCR(ep->epnum - 1)) & FIBCR_BCFX; -- if (length > req->req.length - req->req.actual) -- length = req->req.length - req->req.actual; -- } -- } else { -- buffer = req->req.buf + req->req.actual; -- if (req->req.length - req->req.actual > ep->ep.maxpacket) -- length = ep->ep.maxpacket; -- else -- length = req->req.length - req->req.actual; -- } -- -- d = dma_map_single(dev, buffer, length, -- ep->dir_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); -- -- if (dma_mapping_error(dev, d)) { -- pr_err("dma_mapping_error\n"); -- return; -- } -- -- fotg210_enable_dma(ep, d, length); -- -- /* check if dma is done */ -- fotg210_wait_dma_done(ep); -- -- fotg210_disable_dma(ep); -- -- /* update actual transfer length */ -- req->req.actual += length; -- -- dma_unmap_single(dev, d, length, DMA_TO_DEVICE); --} -- --static void fotg210_ep0_queue(struct fotg210_ep *ep, -- struct fotg210_request *req) --{ -- if (!req->req.length) { -- fotg210_done(ep, req, 0); -- return; -- } -- if (ep->dir_in) { /* if IN */ -- fotg210_start_dma(ep, req); -- if (req->req.length == req->req.actual) -- fotg210_done(ep, req, 0); -- } else { /* OUT */ -- u32 value = ioread32(ep->fotg210->reg + FOTG210_DMISGR0); -- -- value &= ~DMISGR0_MCX_OUT_INT; -- iowrite32(value, ep->fotg210->reg + FOTG210_DMISGR0); -- } --} -- --static int fotg210_ep_queue(struct usb_ep *_ep, struct usb_request *_req, -- gfp_t gfp_flags) --{ -- struct fotg210_ep *ep; -- struct fotg210_request *req; -- unsigned long flags; -- int request = 0; -- -- ep = container_of(_ep, struct fotg210_ep, ep); -- req = container_of(_req, struct fotg210_request, req); -- -- if (ep->fotg210->gadget.speed == USB_SPEED_UNKNOWN) -- return -ESHUTDOWN; -- -- spin_lock_irqsave(&ep->fotg210->lock, flags); -- -- if (list_empty(&ep->queue)) -- request = 1; -- -- list_add_tail(&req->queue, &ep->queue); -- -- req->req.actual = 0; -- req->req.status = -EINPROGRESS; -- -- if (!ep->epnum) /* ep0 */ -- fotg210_ep0_queue(ep, req); -- else if (request && !ep->stall) -- fotg210_enable_fifo_int(ep); -- -- spin_unlock_irqrestore(&ep->fotg210->lock, flags); -- -- return 0; --} -- --static int fotg210_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) --{ -- struct fotg210_ep *ep; -- struct fotg210_request *req; -- unsigned long flags; -- -- ep = container_of(_ep, struct fotg210_ep, ep); -- req = container_of(_req, struct fotg210_request, req); -- -- spin_lock_irqsave(&ep->fotg210->lock, flags); -- if (!list_empty(&ep->queue)) -- fotg210_done(ep, req, -ECONNRESET); -- spin_unlock_irqrestore(&ep->fotg210->lock, flags); -- -- return 0; --} -- --static void fotg210_set_epnstall(struct fotg210_ep *ep) --{ -- struct fotg210_udc *fotg210 = ep->fotg210; -- u32 value; -- void __iomem *reg; -- -- /* check if IN FIFO is empty before stall */ -- if (ep->dir_in) { -- do { -- value = ioread32(fotg210->reg + FOTG210_DCFESR); -- } while (!(value & DCFESR_FIFO_EMPTY(ep->epnum - 1))); -- } -- -- reg = (ep->dir_in) ? -- fotg210->reg + FOTG210_INEPMPSR(ep->epnum) : -- fotg210->reg + FOTG210_OUTEPMPSR(ep->epnum); -- value = ioread32(reg); -- value |= INOUTEPMPSR_STL_EP; -- iowrite32(value, reg); --} -- --static void fotg210_clear_epnstall(struct fotg210_ep *ep) --{ -- struct fotg210_udc *fotg210 = ep->fotg210; -- u32 value; -- void __iomem *reg; -- -- reg = (ep->dir_in) ? -- fotg210->reg + FOTG210_INEPMPSR(ep->epnum) : -- fotg210->reg + FOTG210_OUTEPMPSR(ep->epnum); -- value = ioread32(reg); -- value &= ~INOUTEPMPSR_STL_EP; -- iowrite32(value, reg); --} -- --static int fotg210_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedge) --{ -- struct fotg210_ep *ep; -- struct fotg210_udc *fotg210; -- unsigned long flags; -- -- ep = container_of(_ep, struct fotg210_ep, ep); -- -- fotg210 = ep->fotg210; -- -- spin_lock_irqsave(&ep->fotg210->lock, flags); -- -- if (value) { -- fotg210_set_epnstall(ep); -- ep->stall = 1; -- if (wedge) -- ep->wedged = 1; -- } else { -- fotg210_reset_tseq(fotg210, ep->epnum); -- fotg210_clear_epnstall(ep); -- ep->stall = 0; -- ep->wedged = 0; -- if (!list_empty(&ep->queue)) -- fotg210_enable_fifo_int(ep); -- } -- -- spin_unlock_irqrestore(&ep->fotg210->lock, flags); -- return 0; --} -- --static int fotg210_ep_set_halt(struct usb_ep *_ep, int value) --{ -- return fotg210_set_halt_and_wedge(_ep, value, 0); --} -- --static int fotg210_ep_set_wedge(struct usb_ep *_ep) --{ -- return fotg210_set_halt_and_wedge(_ep, 1, 1); --} -- --static void fotg210_ep_fifo_flush(struct usb_ep *_ep) --{ --} -- --static const struct usb_ep_ops fotg210_ep_ops = { -- .enable = fotg210_ep_enable, -- .disable = fotg210_ep_disable, -- -- .alloc_request = fotg210_ep_alloc_request, -- .free_request = fotg210_ep_free_request, -- -- .queue = fotg210_ep_queue, -- .dequeue = fotg210_ep_dequeue, -- -- .set_halt = fotg210_ep_set_halt, -- .fifo_flush = fotg210_ep_fifo_flush, -- .set_wedge = fotg210_ep_set_wedge, --}; -- --static void fotg210_clear_tx0byte(struct fotg210_udc *fotg210) --{ -- u32 value = ioread32(fotg210->reg + FOTG210_TX0BYTE); -- -- value &= ~(TX0BYTE_EP1 | TX0BYTE_EP2 | TX0BYTE_EP3 -- | TX0BYTE_EP4); -- iowrite32(value, fotg210->reg + FOTG210_TX0BYTE); --} -- --static void fotg210_clear_rx0byte(struct fotg210_udc *fotg210) --{ -- u32 value = ioread32(fotg210->reg + FOTG210_RX0BYTE); -- -- value &= ~(RX0BYTE_EP1 | RX0BYTE_EP2 | RX0BYTE_EP3 -- | RX0BYTE_EP4); -- iowrite32(value, fotg210->reg + FOTG210_RX0BYTE); --} -- --/* read 8-byte setup packet only */ --static void fotg210_rdsetupp(struct fotg210_udc *fotg210, -- u8 *buffer) --{ -- int i = 0; -- u8 *tmp = buffer; -- u32 data; -- u32 length = 8; -- -- iowrite32(DMATFNR_ACC_CXF, fotg210->reg + FOTG210_DMATFNR); -- -- for (i = (length >> 2); i > 0; i--) { -- data = ioread32(fotg210->reg + FOTG210_CXPORT); -- *tmp = data & 0xFF; -- *(tmp + 1) = (data >> 8) & 0xFF; -- *(tmp + 2) = (data >> 16) & 0xFF; -- *(tmp + 3) = (data >> 24) & 0xFF; -- tmp = tmp + 4; -- } -- -- switch (length % 4) { -- case 1: -- data = ioread32(fotg210->reg + FOTG210_CXPORT); -- *tmp = data & 0xFF; -- break; -- case 2: -- data = ioread32(fotg210->reg + FOTG210_CXPORT); -- *tmp = data & 0xFF; -- *(tmp + 1) = (data >> 8) & 0xFF; -- break; -- case 3: -- data = ioread32(fotg210->reg + FOTG210_CXPORT); -- *tmp = data & 0xFF; -- *(tmp + 1) = (data >> 8) & 0xFF; -- *(tmp + 2) = (data >> 16) & 0xFF; -- break; -- default: -- break; -- } -- -- iowrite32(DMATFNR_DISDMA, fotg210->reg + FOTG210_DMATFNR); --} -- --static void fotg210_set_configuration(struct fotg210_udc *fotg210) --{ -- u32 value = ioread32(fotg210->reg + FOTG210_DAR); -- -- value |= DAR_AFT_CONF; -- iowrite32(value, fotg210->reg + FOTG210_DAR); --} -- --static void fotg210_set_dev_addr(struct fotg210_udc *fotg210, u32 addr) --{ -- u32 value = ioread32(fotg210->reg + FOTG210_DAR); -- -- value |= (addr & 0x7F); -- iowrite32(value, fotg210->reg + FOTG210_DAR); --} -- --static void fotg210_set_cxstall(struct fotg210_udc *fotg210) --{ -- u32 value = ioread32(fotg210->reg + FOTG210_DCFESR); -- -- value |= DCFESR_CX_STL; -- iowrite32(value, fotg210->reg + FOTG210_DCFESR); --} -- --static void fotg210_request_error(struct fotg210_udc *fotg210) --{ -- fotg210_set_cxstall(fotg210); -- pr_err("request error!!\n"); --} -- --static void fotg210_set_address(struct fotg210_udc *fotg210, -- struct usb_ctrlrequest *ctrl) --{ -- if (le16_to_cpu(ctrl->wValue) >= 0x0100) { -- fotg210_request_error(fotg210); -- } else { -- fotg210_set_dev_addr(fotg210, le16_to_cpu(ctrl->wValue)); -- fotg210_set_cxdone(fotg210); -- } --} -- --static void fotg210_set_feature(struct fotg210_udc *fotg210, -- struct usb_ctrlrequest *ctrl) --{ -- switch (ctrl->bRequestType & USB_RECIP_MASK) { -- case USB_RECIP_DEVICE: -- fotg210_set_cxdone(fotg210); -- break; -- case USB_RECIP_INTERFACE: -- fotg210_set_cxdone(fotg210); -- break; -- case USB_RECIP_ENDPOINT: { -- u8 epnum; -- epnum = le16_to_cpu(ctrl->wIndex) & USB_ENDPOINT_NUMBER_MASK; -- if (epnum) -- fotg210_set_epnstall(fotg210->ep[epnum]); -- else -- fotg210_set_cxstall(fotg210); -- fotg210_set_cxdone(fotg210); -- } -- break; -- default: -- fotg210_request_error(fotg210); -- break; -- } --} -- --static void fotg210_clear_feature(struct fotg210_udc *fotg210, -- struct usb_ctrlrequest *ctrl) --{ -- struct fotg210_ep *ep = -- fotg210->ep[ctrl->wIndex & USB_ENDPOINT_NUMBER_MASK]; -- -- switch (ctrl->bRequestType & USB_RECIP_MASK) { -- case USB_RECIP_DEVICE: -- fotg210_set_cxdone(fotg210); -- break; -- case USB_RECIP_INTERFACE: -- fotg210_set_cxdone(fotg210); -- break; -- case USB_RECIP_ENDPOINT: -- if (ctrl->wIndex & USB_ENDPOINT_NUMBER_MASK) { -- if (ep->wedged) { -- fotg210_set_cxdone(fotg210); -- break; -- } -- if (ep->stall) -- fotg210_set_halt_and_wedge(&ep->ep, 0, 0); -- } -- fotg210_set_cxdone(fotg210); -- break; -- default: -- fotg210_request_error(fotg210); -- break; -- } --} -- --static int fotg210_is_epnstall(struct fotg210_ep *ep) --{ -- struct fotg210_udc *fotg210 = ep->fotg210; -- u32 value; -- void __iomem *reg; -- -- reg = (ep->dir_in) ? -- fotg210->reg + FOTG210_INEPMPSR(ep->epnum) : -- fotg210->reg + FOTG210_OUTEPMPSR(ep->epnum); -- value = ioread32(reg); -- return value & INOUTEPMPSR_STL_EP ? 1 : 0; --} -- --/* For EP0 requests triggered by this driver (currently GET_STATUS response) */ --static void fotg210_ep0_complete(struct usb_ep *_ep, struct usb_request *req) --{ -- struct fotg210_ep *ep; -- struct fotg210_udc *fotg210; -- -- ep = container_of(_ep, struct fotg210_ep, ep); -- fotg210 = ep->fotg210; -- -- if (req->status || req->actual != req->length) { -- dev_warn(&fotg210->gadget.dev, "EP0 request failed: %d\n", req->status); -- } --} -- --static void fotg210_get_status(struct fotg210_udc *fotg210, -- struct usb_ctrlrequest *ctrl) --{ -- u8 epnum; -- -- switch (ctrl->bRequestType & USB_RECIP_MASK) { -- case USB_RECIP_DEVICE: -- fotg210->ep0_data = cpu_to_le16(1 << USB_DEVICE_SELF_POWERED); -- break; -- case USB_RECIP_INTERFACE: -- fotg210->ep0_data = cpu_to_le16(0); -- break; -- case USB_RECIP_ENDPOINT: -- epnum = ctrl->wIndex & USB_ENDPOINT_NUMBER_MASK; -- if (epnum) -- fotg210->ep0_data = -- cpu_to_le16(fotg210_is_epnstall(fotg210->ep[epnum]) -- << USB_ENDPOINT_HALT); -- else -- fotg210_request_error(fotg210); -- break; -- -- default: -- fotg210_request_error(fotg210); -- return; /* exit */ -- } -- -- fotg210->ep0_req->buf = &fotg210->ep0_data; -- fotg210->ep0_req->length = 2; -- -- spin_unlock(&fotg210->lock); -- fotg210_ep_queue(fotg210->gadget.ep0, fotg210->ep0_req, GFP_ATOMIC); -- spin_lock(&fotg210->lock); --} -- --static int fotg210_setup_packet(struct fotg210_udc *fotg210, -- struct usb_ctrlrequest *ctrl) --{ -- u8 *p = (u8 *)ctrl; -- u8 ret = 0; -- -- fotg210_rdsetupp(fotg210, p); -- -- fotg210->ep[0]->dir_in = ctrl->bRequestType & USB_DIR_IN; -- -- if (fotg210->gadget.speed == USB_SPEED_UNKNOWN) { -- u32 value = ioread32(fotg210->reg + FOTG210_DMCR); -- fotg210->gadget.speed = value & DMCR_HS_EN ? -- USB_SPEED_HIGH : USB_SPEED_FULL; -- } -- -- /* check request */ -- if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { -- switch (ctrl->bRequest) { -- case USB_REQ_GET_STATUS: -- fotg210_get_status(fotg210, ctrl); -- break; -- case USB_REQ_CLEAR_FEATURE: -- fotg210_clear_feature(fotg210, ctrl); -- break; -- case USB_REQ_SET_FEATURE: -- fotg210_set_feature(fotg210, ctrl); -- break; -- case USB_REQ_SET_ADDRESS: -- fotg210_set_address(fotg210, ctrl); -- break; -- case USB_REQ_SET_CONFIGURATION: -- fotg210_set_configuration(fotg210); -- ret = 1; -- break; -- default: -- ret = 1; -- break; -- } -- } else { -- ret = 1; -- } -- -- return ret; --} -- --static void fotg210_ep0out(struct fotg210_udc *fotg210) --{ -- struct fotg210_ep *ep = fotg210->ep[0]; -- -- if (!list_empty(&ep->queue) && !ep->dir_in) { -- struct fotg210_request *req; -- -- req = list_first_entry(&ep->queue, -- struct fotg210_request, queue); -- -- if (req->req.length) -- fotg210_start_dma(ep, req); -- -- if ((req->req.length - req->req.actual) < ep->ep.maxpacket) -- fotg210_done(ep, req, 0); -- } else { -- pr_err("%s : empty queue\n", __func__); -- } --} -- --static void fotg210_ep0in(struct fotg210_udc *fotg210) --{ -- struct fotg210_ep *ep = fotg210->ep[0]; -- -- if ((!list_empty(&ep->queue)) && (ep->dir_in)) { -- struct fotg210_request *req; -- -- req = list_entry(ep->queue.next, -- struct fotg210_request, queue); -- -- if (req->req.length) -- fotg210_start_dma(ep, req); -- -- if (req->req.actual == req->req.length) -- fotg210_done(ep, req, 0); -- } else { -- fotg210_set_cxdone(fotg210); -- } --} -- --static void fotg210_clear_comabt_int(struct fotg210_udc *fotg210) --{ -- u32 value = ioread32(fotg210->reg + FOTG210_DISGR0); -- -- value &= ~DISGR0_CX_COMABT_INT; -- iowrite32(value, fotg210->reg + FOTG210_DISGR0); --} -- --static void fotg210_in_fifo_handler(struct fotg210_ep *ep) --{ -- struct fotg210_request *req = list_entry(ep->queue.next, -- struct fotg210_request, queue); -- -- if (req->req.length) -- fotg210_start_dma(ep, req); -- fotg210_done(ep, req, 0); --} -- --static void fotg210_out_fifo_handler(struct fotg210_ep *ep) --{ -- struct fotg210_request *req = list_entry(ep->queue.next, -- struct fotg210_request, queue); -- int disgr1 = ioread32(ep->fotg210->reg + FOTG210_DISGR1); -- -- fotg210_start_dma(ep, req); -- -- /* Complete the request when it's full or a short packet arrived. -- * Like other drivers, short_not_ok isn't handled. -- */ -- -- if (req->req.length == req->req.actual || -- (disgr1 & DISGR1_SPK_INT(ep->epnum - 1))) -- fotg210_done(ep, req, 0); --} -- --static irqreturn_t fotg210_irq(int irq, void *_fotg210) --{ -- struct fotg210_udc *fotg210 = _fotg210; -- u32 int_grp = ioread32(fotg210->reg + FOTG210_DIGR); -- u32 int_msk = ioread32(fotg210->reg + FOTG210_DMIGR); -- -- int_grp &= ~int_msk; -- -- spin_lock(&fotg210->lock); -- -- if (int_grp & DIGR_INT_G2) { -- void __iomem *reg = fotg210->reg + FOTG210_DISGR2; -- u32 int_grp2 = ioread32(reg); -- u32 int_msk2 = ioread32(fotg210->reg + FOTG210_DMISGR2); -- u32 value; -- -- int_grp2 &= ~int_msk2; -- -- if (int_grp2 & DISGR2_USBRST_INT) { -- usb_gadget_udc_reset(&fotg210->gadget, -- fotg210->driver); -- value = ioread32(reg); -- value &= ~DISGR2_USBRST_INT; -- iowrite32(value, reg); -- pr_info("fotg210 udc reset\n"); -- } -- if (int_grp2 & DISGR2_SUSP_INT) { -- value = ioread32(reg); -- value &= ~DISGR2_SUSP_INT; -- iowrite32(value, reg); -- pr_info("fotg210 udc suspend\n"); -- } -- if (int_grp2 & DISGR2_RESM_INT) { -- value = ioread32(reg); -- value &= ~DISGR2_RESM_INT; -- iowrite32(value, reg); -- pr_info("fotg210 udc resume\n"); -- } -- if (int_grp2 & DISGR2_ISO_SEQ_ERR_INT) { -- value = ioread32(reg); -- value &= ~DISGR2_ISO_SEQ_ERR_INT; -- iowrite32(value, reg); -- pr_info("fotg210 iso sequence error\n"); -- } -- if (int_grp2 & DISGR2_ISO_SEQ_ABORT_INT) { -- value = ioread32(reg); -- value &= ~DISGR2_ISO_SEQ_ABORT_INT; -- iowrite32(value, reg); -- pr_info("fotg210 iso sequence abort\n"); -- } -- if (int_grp2 & DISGR2_TX0BYTE_INT) { -- fotg210_clear_tx0byte(fotg210); -- value = ioread32(reg); -- value &= ~DISGR2_TX0BYTE_INT; -- iowrite32(value, reg); -- pr_info("fotg210 transferred 0 byte\n"); -- } -- if (int_grp2 & DISGR2_RX0BYTE_INT) { -- fotg210_clear_rx0byte(fotg210); -- value = ioread32(reg); -- value &= ~DISGR2_RX0BYTE_INT; -- iowrite32(value, reg); -- pr_info("fotg210 received 0 byte\n"); -- } -- if (int_grp2 & DISGR2_DMA_ERROR) { -- value = ioread32(reg); -- value &= ~DISGR2_DMA_ERROR; -- iowrite32(value, reg); -- } -- } -- -- if (int_grp & DIGR_INT_G0) { -- void __iomem *reg = fotg210->reg + FOTG210_DISGR0; -- u32 int_grp0 = ioread32(reg); -- u32 int_msk0 = ioread32(fotg210->reg + FOTG210_DMISGR0); -- struct usb_ctrlrequest ctrl; -- -- int_grp0 &= ~int_msk0; -- -- /* the highest priority in this source register */ -- if (int_grp0 & DISGR0_CX_COMABT_INT) { -- fotg210_clear_comabt_int(fotg210); -- pr_info("fotg210 CX command abort\n"); -- } -- -- if (int_grp0 & DISGR0_CX_SETUP_INT) { -- if (fotg210_setup_packet(fotg210, &ctrl)) { -- spin_unlock(&fotg210->lock); -- if (fotg210->driver->setup(&fotg210->gadget, -- &ctrl) < 0) -- fotg210_set_cxstall(fotg210); -- spin_lock(&fotg210->lock); -- } -- } -- if (int_grp0 & DISGR0_CX_COMEND_INT) -- pr_info("fotg210 cmd end\n"); -- -- if (int_grp0 & DISGR0_CX_IN_INT) -- fotg210_ep0in(fotg210); -- -- if (int_grp0 & DISGR0_CX_OUT_INT) -- fotg210_ep0out(fotg210); -- -- if (int_grp0 & DISGR0_CX_COMFAIL_INT) { -- fotg210_set_cxstall(fotg210); -- pr_info("fotg210 ep0 fail\n"); -- } -- } -- -- if (int_grp & DIGR_INT_G1) { -- void __iomem *reg = fotg210->reg + FOTG210_DISGR1; -- u32 int_grp1 = ioread32(reg); -- u32 int_msk1 = ioread32(fotg210->reg + FOTG210_DMISGR1); -- int fifo; -- -- int_grp1 &= ~int_msk1; -- -- for (fifo = 0; fifo < FOTG210_MAX_FIFO_NUM; fifo++) { -- if (int_grp1 & DISGR1_IN_INT(fifo)) -- fotg210_in_fifo_handler(fotg210->ep[fifo + 1]); -- -- if ((int_grp1 & DISGR1_OUT_INT(fifo)) || -- (int_grp1 & DISGR1_SPK_INT(fifo))) -- fotg210_out_fifo_handler(fotg210->ep[fifo + 1]); -- } -- } -- -- spin_unlock(&fotg210->lock); -- -- return IRQ_HANDLED; --} -- --static void fotg210_disable_unplug(struct fotg210_udc *fotg210) --{ -- u32 reg = ioread32(fotg210->reg + FOTG210_PHYTMSR); -- -- reg &= ~PHYTMSR_UNPLUG; -- iowrite32(reg, fotg210->reg + FOTG210_PHYTMSR); --} -- --static int fotg210_udc_start(struct usb_gadget *g, -- struct usb_gadget_driver *driver) --{ -- struct fotg210_udc *fotg210 = gadget_to_fotg210(g); -- u32 value; -- -- /* hook up the driver */ -- fotg210->driver = driver; -- -- /* enable device global interrupt */ -- value = ioread32(fotg210->reg + FOTG210_DMCR); -- value |= DMCR_GLINT_EN; -- iowrite32(value, fotg210->reg + FOTG210_DMCR); -- -- return 0; --} -- --static void fotg210_init(struct fotg210_udc *fotg210) --{ -- u32 value; -- -- /* disable global interrupt and set int polarity to active high */ -- iowrite32(GMIR_MHC_INT | GMIR_MOTG_INT | GMIR_INT_POLARITY, -- fotg210->reg + FOTG210_GMIR); -- -- /* disable device global interrupt */ -- value = ioread32(fotg210->reg + FOTG210_DMCR); -- value &= ~DMCR_GLINT_EN; -- iowrite32(value, fotg210->reg + FOTG210_DMCR); -- -- /* enable only grp2 irqs we handle */ -- iowrite32(~(DISGR2_DMA_ERROR | DISGR2_RX0BYTE_INT | DISGR2_TX0BYTE_INT -- | DISGR2_ISO_SEQ_ABORT_INT | DISGR2_ISO_SEQ_ERR_INT -- | DISGR2_RESM_INT | DISGR2_SUSP_INT | DISGR2_USBRST_INT), -- fotg210->reg + FOTG210_DMISGR2); -- -- /* disable all fifo interrupt */ -- iowrite32(~(u32)0, fotg210->reg + FOTG210_DMISGR1); -- -- /* disable cmd end */ -- value = ioread32(fotg210->reg + FOTG210_DMISGR0); -- value |= DMISGR0_MCX_COMEND; -- iowrite32(value, fotg210->reg + FOTG210_DMISGR0); --} -- --static int fotg210_udc_stop(struct usb_gadget *g) --{ -- struct fotg210_udc *fotg210 = gadget_to_fotg210(g); -- unsigned long flags; -- -- spin_lock_irqsave(&fotg210->lock, flags); -- -- fotg210_init(fotg210); -- fotg210->driver = NULL; -- -- spin_unlock_irqrestore(&fotg210->lock, flags); -- -- return 0; --} -- --static const struct usb_gadget_ops fotg210_gadget_ops = { -- .udc_start = fotg210_udc_start, -- .udc_stop = fotg210_udc_stop, --}; -- --static int fotg210_udc_remove(struct platform_device *pdev) --{ -- struct fotg210_udc *fotg210 = platform_get_drvdata(pdev); -- int i; -- -- usb_del_gadget_udc(&fotg210->gadget); -- iounmap(fotg210->reg); -- free_irq(platform_get_irq(pdev, 0), fotg210); -- -- fotg210_ep_free_request(&fotg210->ep[0]->ep, fotg210->ep0_req); -- for (i = 0; i < FOTG210_MAX_NUM_EP; i++) -- kfree(fotg210->ep[i]); -- kfree(fotg210); -- -- return 0; --} -- --static int fotg210_udc_probe(struct platform_device *pdev) --{ -- struct resource *res, *ires; -- struct fotg210_udc *fotg210 = NULL; -- struct fotg210_ep *_ep[FOTG210_MAX_NUM_EP]; -- int ret = 0; -- int i; -- -- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -- if (!res) { -- pr_err("platform_get_resource error.\n"); -- return -ENODEV; -- } -- -- ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0); -- if (!ires) { -- pr_err("platform_get_resource IORESOURCE_IRQ error.\n"); -- return -ENODEV; -- } -- -- ret = -ENOMEM; -- -- /* initialize udc */ -- fotg210 = kzalloc(sizeof(struct fotg210_udc), GFP_KERNEL); -- if (fotg210 == NULL) -- goto err; -- -- for (i = 0; i < FOTG210_MAX_NUM_EP; i++) { -- _ep[i] = kzalloc(sizeof(struct fotg210_ep), GFP_KERNEL); -- if (_ep[i] == NULL) -- goto err_alloc; -- fotg210->ep[i] = _ep[i]; -- } -- -- fotg210->reg = ioremap(res->start, resource_size(res)); -- if (fotg210->reg == NULL) { -- pr_err("ioremap error.\n"); -- goto err_alloc; -- } -- -- spin_lock_init(&fotg210->lock); -- -- platform_set_drvdata(pdev, fotg210); -- -- fotg210->gadget.ops = &fotg210_gadget_ops; -- -- fotg210->gadget.max_speed = USB_SPEED_HIGH; -- fotg210->gadget.dev.parent = &pdev->dev; -- fotg210->gadget.dev.dma_mask = pdev->dev.dma_mask; -- fotg210->gadget.name = udc_name; -- -- INIT_LIST_HEAD(&fotg210->gadget.ep_list); -- -- for (i = 0; i < FOTG210_MAX_NUM_EP; i++) { -- struct fotg210_ep *ep = fotg210->ep[i]; -- -- if (i) { -- INIT_LIST_HEAD(&fotg210->ep[i]->ep.ep_list); -- list_add_tail(&fotg210->ep[i]->ep.ep_list, -- &fotg210->gadget.ep_list); -- } -- ep->fotg210 = fotg210; -- INIT_LIST_HEAD(&ep->queue); -- ep->ep.name = fotg210_ep_name[i]; -- ep->ep.ops = &fotg210_ep_ops; -- usb_ep_set_maxpacket_limit(&ep->ep, (unsigned short) ~0); -- -- if (i == 0) { -- ep->ep.caps.type_control = true; -- } else { -- ep->ep.caps.type_iso = true; -- ep->ep.caps.type_bulk = true; -- ep->ep.caps.type_int = true; -- } -- -- ep->ep.caps.dir_in = true; -- ep->ep.caps.dir_out = true; -- } -- usb_ep_set_maxpacket_limit(&fotg210->ep[0]->ep, 0x40); -- fotg210->gadget.ep0 = &fotg210->ep[0]->ep; -- INIT_LIST_HEAD(&fotg210->gadget.ep0->ep_list); -- -- fotg210->ep0_req = fotg210_ep_alloc_request(&fotg210->ep[0]->ep, -- GFP_KERNEL); -- if (fotg210->ep0_req == NULL) -- goto err_map; -- -- fotg210->ep0_req->complete = fotg210_ep0_complete; -- -- fotg210_init(fotg210); -- -- fotg210_disable_unplug(fotg210); -- -- ret = request_irq(ires->start, fotg210_irq, IRQF_SHARED, -- udc_name, fotg210); -- if (ret < 0) { -- pr_err("request_irq error (%d)\n", ret); -- goto err_req; -- } -- -- ret = usb_add_gadget_udc(&pdev->dev, &fotg210->gadget); -- if (ret) -- goto err_add_udc; -- -- dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION); -- -- return 0; -- --err_add_udc: -- free_irq(ires->start, fotg210); -- --err_req: -- fotg210_ep_free_request(&fotg210->ep[0]->ep, fotg210->ep0_req); -- --err_map: -- iounmap(fotg210->reg); -- --err_alloc: -- for (i = 0; i < FOTG210_MAX_NUM_EP; i++) -- kfree(fotg210->ep[i]); -- kfree(fotg210); -- --err: -- return ret; --} -- --static struct platform_driver fotg210_driver = { -- .driver = { -- .name = udc_name, -- }, -- .probe = fotg210_udc_probe, -- .remove = fotg210_udc_remove, --}; -- --module_platform_driver(fotg210_driver); -- --MODULE_AUTHOR("Yuan-Hsin Chen, Feng-Hsin Chiang "); --MODULE_LICENSE("GPL"); --MODULE_DESCRIPTION(DRIVER_DESC); ---- /dev/null -+++ b/drivers/usb/fotg210/fotg210-udc.c -@@ -0,0 +1,1239 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * FOTG210 UDC Driver supports Bulk transfer so far -+ * -+ * Copyright (C) 2013 Faraday Technology Corporation -+ * -+ * Author : Yuan-Hsin Chen -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "fotg210-udc.h" -+ -+#define DRIVER_DESC "FOTG210 USB Device Controller Driver" -+#define DRIVER_VERSION "30-April-2013" -+ -+static const char udc_name[] = "fotg210_udc"; -+static const char * const fotg210_ep_name[] = { -+ "ep0", "ep1", "ep2", "ep3", "ep4"}; -+ -+static void fotg210_disable_fifo_int(struct fotg210_ep *ep) -+{ -+ u32 value = ioread32(ep->fotg210->reg + FOTG210_DMISGR1); -+ -+ if (ep->dir_in) -+ value |= DMISGR1_MF_IN_INT(ep->epnum - 1); -+ else -+ value |= DMISGR1_MF_OUTSPK_INT(ep->epnum - 1); -+ iowrite32(value, ep->fotg210->reg + FOTG210_DMISGR1); -+} -+ -+static void fotg210_enable_fifo_int(struct fotg210_ep *ep) -+{ -+ u32 value = ioread32(ep->fotg210->reg + FOTG210_DMISGR1); -+ -+ if (ep->dir_in) -+ value &= ~DMISGR1_MF_IN_INT(ep->epnum - 1); -+ else -+ value &= ~DMISGR1_MF_OUTSPK_INT(ep->epnum - 1); -+ iowrite32(value, ep->fotg210->reg + FOTG210_DMISGR1); -+} -+ -+static void fotg210_set_cxdone(struct fotg210_udc *fotg210) -+{ -+ u32 value = ioread32(fotg210->reg + FOTG210_DCFESR); -+ -+ value |= DCFESR_CX_DONE; -+ iowrite32(value, fotg210->reg + FOTG210_DCFESR); -+} -+ -+static void fotg210_done(struct fotg210_ep *ep, struct fotg210_request *req, -+ int status) -+{ -+ list_del_init(&req->queue); -+ -+ /* don't modify queue heads during completion callback */ -+ if (ep->fotg210->gadget.speed == USB_SPEED_UNKNOWN) -+ req->req.status = -ESHUTDOWN; -+ else -+ req->req.status = status; -+ -+ spin_unlock(&ep->fotg210->lock); -+ usb_gadget_giveback_request(&ep->ep, &req->req); -+ spin_lock(&ep->fotg210->lock); -+ -+ if (ep->epnum) { -+ if (list_empty(&ep->queue)) -+ fotg210_disable_fifo_int(ep); -+ } else { -+ fotg210_set_cxdone(ep->fotg210); -+ } -+} -+ -+static void fotg210_fifo_ep_mapping(struct fotg210_ep *ep, u32 epnum, -+ u32 dir_in) -+{ -+ struct fotg210_udc *fotg210 = ep->fotg210; -+ u32 val; -+ -+ /* Driver should map an ep to a fifo and then map the fifo -+ * to the ep. What a brain-damaged design! -+ */ -+ -+ /* map a fifo to an ep */ -+ val = ioread32(fotg210->reg + FOTG210_EPMAP); -+ val &= ~EPMAP_FIFONOMSK(epnum, dir_in); -+ val |= EPMAP_FIFONO(epnum, dir_in); -+ iowrite32(val, fotg210->reg + FOTG210_EPMAP); -+ -+ /* map the ep to the fifo */ -+ val = ioread32(fotg210->reg + FOTG210_FIFOMAP); -+ val &= ~FIFOMAP_EPNOMSK(epnum); -+ val |= FIFOMAP_EPNO(epnum); -+ iowrite32(val, fotg210->reg + FOTG210_FIFOMAP); -+ -+ /* enable fifo */ -+ val = ioread32(fotg210->reg + FOTG210_FIFOCF); -+ val |= FIFOCF_FIFO_EN(epnum - 1); -+ iowrite32(val, fotg210->reg + FOTG210_FIFOCF); -+} -+ -+static void fotg210_set_fifo_dir(struct fotg210_ep *ep, u32 epnum, u32 dir_in) -+{ -+ struct fotg210_udc *fotg210 = ep->fotg210; -+ u32 val; -+ -+ val = ioread32(fotg210->reg + FOTG210_FIFOMAP); -+ val |= (dir_in ? FIFOMAP_DIRIN(epnum - 1) : FIFOMAP_DIROUT(epnum - 1)); -+ iowrite32(val, fotg210->reg + FOTG210_FIFOMAP); -+} -+ -+static void fotg210_set_tfrtype(struct fotg210_ep *ep, u32 epnum, u32 type) -+{ -+ struct fotg210_udc *fotg210 = ep->fotg210; -+ u32 val; -+ -+ val = ioread32(fotg210->reg + FOTG210_FIFOCF); -+ val |= FIFOCF_TYPE(type, epnum - 1); -+ iowrite32(val, fotg210->reg + FOTG210_FIFOCF); -+} -+ -+static void fotg210_set_mps(struct fotg210_ep *ep, u32 epnum, u32 mps, -+ u32 dir_in) -+{ -+ struct fotg210_udc *fotg210 = ep->fotg210; -+ u32 val; -+ u32 offset = dir_in ? FOTG210_INEPMPSR(epnum) : -+ FOTG210_OUTEPMPSR(epnum); -+ -+ val = ioread32(fotg210->reg + offset); -+ val |= INOUTEPMPSR_MPS(mps); -+ iowrite32(val, fotg210->reg + offset); -+} -+ -+static int fotg210_config_ep(struct fotg210_ep *ep, -+ const struct usb_endpoint_descriptor *desc) -+{ -+ struct fotg210_udc *fotg210 = ep->fotg210; -+ -+ fotg210_set_fifo_dir(ep, ep->epnum, ep->dir_in); -+ fotg210_set_tfrtype(ep, ep->epnum, ep->type); -+ fotg210_set_mps(ep, ep->epnum, ep->ep.maxpacket, ep->dir_in); -+ fotg210_fifo_ep_mapping(ep, ep->epnum, ep->dir_in); -+ -+ fotg210->ep[ep->epnum] = ep; -+ -+ return 0; -+} -+ -+static int fotg210_ep_enable(struct usb_ep *_ep, -+ const struct usb_endpoint_descriptor *desc) -+{ -+ struct fotg210_ep *ep; -+ -+ ep = container_of(_ep, struct fotg210_ep, ep); -+ -+ ep->desc = desc; -+ ep->epnum = usb_endpoint_num(desc); -+ ep->type = usb_endpoint_type(desc); -+ ep->dir_in = usb_endpoint_dir_in(desc); -+ ep->ep.maxpacket = usb_endpoint_maxp(desc); -+ -+ return fotg210_config_ep(ep, desc); -+} -+ -+static void fotg210_reset_tseq(struct fotg210_udc *fotg210, u8 epnum) -+{ -+ struct fotg210_ep *ep = fotg210->ep[epnum]; -+ u32 value; -+ void __iomem *reg; -+ -+ reg = (ep->dir_in) ? -+ fotg210->reg + FOTG210_INEPMPSR(epnum) : -+ fotg210->reg + FOTG210_OUTEPMPSR(epnum); -+ -+ /* Note: Driver needs to set and clear INOUTEPMPSR_RESET_TSEQ -+ * bit. Controller wouldn't clear this bit. WTF!!! -+ */ -+ -+ value = ioread32(reg); -+ value |= INOUTEPMPSR_RESET_TSEQ; -+ iowrite32(value, reg); -+ -+ value = ioread32(reg); -+ value &= ~INOUTEPMPSR_RESET_TSEQ; -+ iowrite32(value, reg); -+} -+ -+static int fotg210_ep_release(struct fotg210_ep *ep) -+{ -+ if (!ep->epnum) -+ return 0; -+ ep->epnum = 0; -+ ep->stall = 0; -+ ep->wedged = 0; -+ -+ fotg210_reset_tseq(ep->fotg210, ep->epnum); -+ -+ return 0; -+} -+ -+static int fotg210_ep_disable(struct usb_ep *_ep) -+{ -+ struct fotg210_ep *ep; -+ struct fotg210_request *req; -+ unsigned long flags; -+ -+ BUG_ON(!_ep); -+ -+ ep = container_of(_ep, struct fotg210_ep, ep); -+ -+ while (!list_empty(&ep->queue)) { -+ req = list_entry(ep->queue.next, -+ struct fotg210_request, queue); -+ spin_lock_irqsave(&ep->fotg210->lock, flags); -+ fotg210_done(ep, req, -ECONNRESET); -+ spin_unlock_irqrestore(&ep->fotg210->lock, flags); -+ } -+ -+ return fotg210_ep_release(ep); -+} -+ -+static struct usb_request *fotg210_ep_alloc_request(struct usb_ep *_ep, -+ gfp_t gfp_flags) -+{ -+ struct fotg210_request *req; -+ -+ req = kzalloc(sizeof(struct fotg210_request), gfp_flags); -+ if (!req) -+ return NULL; -+ -+ INIT_LIST_HEAD(&req->queue); -+ -+ return &req->req; -+} -+ -+static void fotg210_ep_free_request(struct usb_ep *_ep, -+ struct usb_request *_req) -+{ -+ struct fotg210_request *req; -+ -+ req = container_of(_req, struct fotg210_request, req); -+ kfree(req); -+} -+ -+static void fotg210_enable_dma(struct fotg210_ep *ep, -+ dma_addr_t d, u32 len) -+{ -+ u32 value; -+ struct fotg210_udc *fotg210 = ep->fotg210; -+ -+ /* set transfer length and direction */ -+ value = ioread32(fotg210->reg + FOTG210_DMACPSR1); -+ value &= ~(DMACPSR1_DMA_LEN(0xFFFF) | DMACPSR1_DMA_TYPE(1)); -+ value |= DMACPSR1_DMA_LEN(len) | DMACPSR1_DMA_TYPE(ep->dir_in); -+ iowrite32(value, fotg210->reg + FOTG210_DMACPSR1); -+ -+ /* set device DMA target FIFO number */ -+ value = ioread32(fotg210->reg + FOTG210_DMATFNR); -+ if (ep->epnum) -+ value |= DMATFNR_ACC_FN(ep->epnum - 1); -+ else -+ value |= DMATFNR_ACC_CXF; -+ iowrite32(value, fotg210->reg + FOTG210_DMATFNR); -+ -+ /* set DMA memory address */ -+ iowrite32(d, fotg210->reg + FOTG210_DMACPSR2); -+ -+ /* enable MDMA_EROR and MDMA_CMPLT interrupt */ -+ value = ioread32(fotg210->reg + FOTG210_DMISGR2); -+ value &= ~(DMISGR2_MDMA_CMPLT | DMISGR2_MDMA_ERROR); -+ iowrite32(value, fotg210->reg + FOTG210_DMISGR2); -+ -+ /* start DMA */ -+ value = ioread32(fotg210->reg + FOTG210_DMACPSR1); -+ value |= DMACPSR1_DMA_START; -+ iowrite32(value, fotg210->reg + FOTG210_DMACPSR1); -+} -+ -+static void fotg210_disable_dma(struct fotg210_ep *ep) -+{ -+ iowrite32(DMATFNR_DISDMA, ep->fotg210->reg + FOTG210_DMATFNR); -+} -+ -+static void fotg210_wait_dma_done(struct fotg210_ep *ep) -+{ -+ u32 value; -+ -+ do { -+ value = ioread32(ep->fotg210->reg + FOTG210_DISGR2); -+ if ((value & DISGR2_USBRST_INT) || -+ (value & DISGR2_DMA_ERROR)) -+ goto dma_reset; -+ } while (!(value & DISGR2_DMA_CMPLT)); -+ -+ value &= ~DISGR2_DMA_CMPLT; -+ iowrite32(value, ep->fotg210->reg + FOTG210_DISGR2); -+ return; -+ -+dma_reset: -+ value = ioread32(ep->fotg210->reg + FOTG210_DMACPSR1); -+ value |= DMACPSR1_DMA_ABORT; -+ iowrite32(value, ep->fotg210->reg + FOTG210_DMACPSR1); -+ -+ /* reset fifo */ -+ if (ep->epnum) { -+ value = ioread32(ep->fotg210->reg + -+ FOTG210_FIBCR(ep->epnum - 1)); -+ value |= FIBCR_FFRST; -+ iowrite32(value, ep->fotg210->reg + -+ FOTG210_FIBCR(ep->epnum - 1)); -+ } else { -+ value = ioread32(ep->fotg210->reg + FOTG210_DCFESR); -+ value |= DCFESR_CX_CLR; -+ iowrite32(value, ep->fotg210->reg + FOTG210_DCFESR); -+ } -+} -+ -+static void fotg210_start_dma(struct fotg210_ep *ep, -+ struct fotg210_request *req) -+{ -+ struct device *dev = &ep->fotg210->gadget.dev; -+ dma_addr_t d; -+ u8 *buffer; -+ u32 length; -+ -+ if (ep->epnum) { -+ if (ep->dir_in) { -+ buffer = req->req.buf; -+ length = req->req.length; -+ } else { -+ buffer = req->req.buf + req->req.actual; -+ length = ioread32(ep->fotg210->reg + -+ FOTG210_FIBCR(ep->epnum - 1)) & FIBCR_BCFX; -+ if (length > req->req.length - req->req.actual) -+ length = req->req.length - req->req.actual; -+ } -+ } else { -+ buffer = req->req.buf + req->req.actual; -+ if (req->req.length - req->req.actual > ep->ep.maxpacket) -+ length = ep->ep.maxpacket; -+ else -+ length = req->req.length - req->req.actual; -+ } -+ -+ d = dma_map_single(dev, buffer, length, -+ ep->dir_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); -+ -+ if (dma_mapping_error(dev, d)) { -+ pr_err("dma_mapping_error\n"); -+ return; -+ } -+ -+ fotg210_enable_dma(ep, d, length); -+ -+ /* check if dma is done */ -+ fotg210_wait_dma_done(ep); -+ -+ fotg210_disable_dma(ep); -+ -+ /* update actual transfer length */ -+ req->req.actual += length; -+ -+ dma_unmap_single(dev, d, length, DMA_TO_DEVICE); -+} -+ -+static void fotg210_ep0_queue(struct fotg210_ep *ep, -+ struct fotg210_request *req) -+{ -+ if (!req->req.length) { -+ fotg210_done(ep, req, 0); -+ return; -+ } -+ if (ep->dir_in) { /* if IN */ -+ fotg210_start_dma(ep, req); -+ if (req->req.length == req->req.actual) -+ fotg210_done(ep, req, 0); -+ } else { /* OUT */ -+ u32 value = ioread32(ep->fotg210->reg + FOTG210_DMISGR0); -+ -+ value &= ~DMISGR0_MCX_OUT_INT; -+ iowrite32(value, ep->fotg210->reg + FOTG210_DMISGR0); -+ } -+} -+ -+static int fotg210_ep_queue(struct usb_ep *_ep, struct usb_request *_req, -+ gfp_t gfp_flags) -+{ -+ struct fotg210_ep *ep; -+ struct fotg210_request *req; -+ unsigned long flags; -+ int request = 0; -+ -+ ep = container_of(_ep, struct fotg210_ep, ep); -+ req = container_of(_req, struct fotg210_request, req); -+ -+ if (ep->fotg210->gadget.speed == USB_SPEED_UNKNOWN) -+ return -ESHUTDOWN; -+ -+ spin_lock_irqsave(&ep->fotg210->lock, flags); -+ -+ if (list_empty(&ep->queue)) -+ request = 1; -+ -+ list_add_tail(&req->queue, &ep->queue); -+ -+ req->req.actual = 0; -+ req->req.status = -EINPROGRESS; -+ -+ if (!ep->epnum) /* ep0 */ -+ fotg210_ep0_queue(ep, req); -+ else if (request && !ep->stall) -+ fotg210_enable_fifo_int(ep); -+ -+ spin_unlock_irqrestore(&ep->fotg210->lock, flags); -+ -+ return 0; -+} -+ -+static int fotg210_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) -+{ -+ struct fotg210_ep *ep; -+ struct fotg210_request *req; -+ unsigned long flags; -+ -+ ep = container_of(_ep, struct fotg210_ep, ep); -+ req = container_of(_req, struct fotg210_request, req); -+ -+ spin_lock_irqsave(&ep->fotg210->lock, flags); -+ if (!list_empty(&ep->queue)) -+ fotg210_done(ep, req, -ECONNRESET); -+ spin_unlock_irqrestore(&ep->fotg210->lock, flags); -+ -+ return 0; -+} -+ -+static void fotg210_set_epnstall(struct fotg210_ep *ep) -+{ -+ struct fotg210_udc *fotg210 = ep->fotg210; -+ u32 value; -+ void __iomem *reg; -+ -+ /* check if IN FIFO is empty before stall */ -+ if (ep->dir_in) { -+ do { -+ value = ioread32(fotg210->reg + FOTG210_DCFESR); -+ } while (!(value & DCFESR_FIFO_EMPTY(ep->epnum - 1))); -+ } -+ -+ reg = (ep->dir_in) ? -+ fotg210->reg + FOTG210_INEPMPSR(ep->epnum) : -+ fotg210->reg + FOTG210_OUTEPMPSR(ep->epnum); -+ value = ioread32(reg); -+ value |= INOUTEPMPSR_STL_EP; -+ iowrite32(value, reg); -+} -+ -+static void fotg210_clear_epnstall(struct fotg210_ep *ep) -+{ -+ struct fotg210_udc *fotg210 = ep->fotg210; -+ u32 value; -+ void __iomem *reg; -+ -+ reg = (ep->dir_in) ? -+ fotg210->reg + FOTG210_INEPMPSR(ep->epnum) : -+ fotg210->reg + FOTG210_OUTEPMPSR(ep->epnum); -+ value = ioread32(reg); -+ value &= ~INOUTEPMPSR_STL_EP; -+ iowrite32(value, reg); -+} -+ -+static int fotg210_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedge) -+{ -+ struct fotg210_ep *ep; -+ struct fotg210_udc *fotg210; -+ unsigned long flags; -+ -+ ep = container_of(_ep, struct fotg210_ep, ep); -+ -+ fotg210 = ep->fotg210; -+ -+ spin_lock_irqsave(&ep->fotg210->lock, flags); -+ -+ if (value) { -+ fotg210_set_epnstall(ep); -+ ep->stall = 1; -+ if (wedge) -+ ep->wedged = 1; -+ } else { -+ fotg210_reset_tseq(fotg210, ep->epnum); -+ fotg210_clear_epnstall(ep); -+ ep->stall = 0; -+ ep->wedged = 0; -+ if (!list_empty(&ep->queue)) -+ fotg210_enable_fifo_int(ep); -+ } -+ -+ spin_unlock_irqrestore(&ep->fotg210->lock, flags); -+ return 0; -+} -+ -+static int fotg210_ep_set_halt(struct usb_ep *_ep, int value) -+{ -+ return fotg210_set_halt_and_wedge(_ep, value, 0); -+} -+ -+static int fotg210_ep_set_wedge(struct usb_ep *_ep) -+{ -+ return fotg210_set_halt_and_wedge(_ep, 1, 1); -+} -+ -+static void fotg210_ep_fifo_flush(struct usb_ep *_ep) -+{ -+} -+ -+static const struct usb_ep_ops fotg210_ep_ops = { -+ .enable = fotg210_ep_enable, -+ .disable = fotg210_ep_disable, -+ -+ .alloc_request = fotg210_ep_alloc_request, -+ .free_request = fotg210_ep_free_request, -+ -+ .queue = fotg210_ep_queue, -+ .dequeue = fotg210_ep_dequeue, -+ -+ .set_halt = fotg210_ep_set_halt, -+ .fifo_flush = fotg210_ep_fifo_flush, -+ .set_wedge = fotg210_ep_set_wedge, -+}; -+ -+static void fotg210_clear_tx0byte(struct fotg210_udc *fotg210) -+{ -+ u32 value = ioread32(fotg210->reg + FOTG210_TX0BYTE); -+ -+ value &= ~(TX0BYTE_EP1 | TX0BYTE_EP2 | TX0BYTE_EP3 -+ | TX0BYTE_EP4); -+ iowrite32(value, fotg210->reg + FOTG210_TX0BYTE); -+} -+ -+static void fotg210_clear_rx0byte(struct fotg210_udc *fotg210) -+{ -+ u32 value = ioread32(fotg210->reg + FOTG210_RX0BYTE); -+ -+ value &= ~(RX0BYTE_EP1 | RX0BYTE_EP2 | RX0BYTE_EP3 -+ | RX0BYTE_EP4); -+ iowrite32(value, fotg210->reg + FOTG210_RX0BYTE); -+} -+ -+/* read 8-byte setup packet only */ -+static void fotg210_rdsetupp(struct fotg210_udc *fotg210, -+ u8 *buffer) -+{ -+ int i = 0; -+ u8 *tmp = buffer; -+ u32 data; -+ u32 length = 8; -+ -+ iowrite32(DMATFNR_ACC_CXF, fotg210->reg + FOTG210_DMATFNR); -+ -+ for (i = (length >> 2); i > 0; i--) { -+ data = ioread32(fotg210->reg + FOTG210_CXPORT); -+ *tmp = data & 0xFF; -+ *(tmp + 1) = (data >> 8) & 0xFF; -+ *(tmp + 2) = (data >> 16) & 0xFF; -+ *(tmp + 3) = (data >> 24) & 0xFF; -+ tmp = tmp + 4; -+ } -+ -+ switch (length % 4) { -+ case 1: -+ data = ioread32(fotg210->reg + FOTG210_CXPORT); -+ *tmp = data & 0xFF; -+ break; -+ case 2: -+ data = ioread32(fotg210->reg + FOTG210_CXPORT); -+ *tmp = data & 0xFF; -+ *(tmp + 1) = (data >> 8) & 0xFF; -+ break; -+ case 3: -+ data = ioread32(fotg210->reg + FOTG210_CXPORT); -+ *tmp = data & 0xFF; -+ *(tmp + 1) = (data >> 8) & 0xFF; -+ *(tmp + 2) = (data >> 16) & 0xFF; -+ break; -+ default: -+ break; -+ } -+ -+ iowrite32(DMATFNR_DISDMA, fotg210->reg + FOTG210_DMATFNR); -+} -+ -+static void fotg210_set_configuration(struct fotg210_udc *fotg210) -+{ -+ u32 value = ioread32(fotg210->reg + FOTG210_DAR); -+ -+ value |= DAR_AFT_CONF; -+ iowrite32(value, fotg210->reg + FOTG210_DAR); -+} -+ -+static void fotg210_set_dev_addr(struct fotg210_udc *fotg210, u32 addr) -+{ -+ u32 value = ioread32(fotg210->reg + FOTG210_DAR); -+ -+ value |= (addr & 0x7F); -+ iowrite32(value, fotg210->reg + FOTG210_DAR); -+} -+ -+static void fotg210_set_cxstall(struct fotg210_udc *fotg210) -+{ -+ u32 value = ioread32(fotg210->reg + FOTG210_DCFESR); -+ -+ value |= DCFESR_CX_STL; -+ iowrite32(value, fotg210->reg + FOTG210_DCFESR); -+} -+ -+static void fotg210_request_error(struct fotg210_udc *fotg210) -+{ -+ fotg210_set_cxstall(fotg210); -+ pr_err("request error!!\n"); -+} -+ -+static void fotg210_set_address(struct fotg210_udc *fotg210, -+ struct usb_ctrlrequest *ctrl) -+{ -+ if (le16_to_cpu(ctrl->wValue) >= 0x0100) { -+ fotg210_request_error(fotg210); -+ } else { -+ fotg210_set_dev_addr(fotg210, le16_to_cpu(ctrl->wValue)); -+ fotg210_set_cxdone(fotg210); -+ } -+} -+ -+static void fotg210_set_feature(struct fotg210_udc *fotg210, -+ struct usb_ctrlrequest *ctrl) -+{ -+ switch (ctrl->bRequestType & USB_RECIP_MASK) { -+ case USB_RECIP_DEVICE: -+ fotg210_set_cxdone(fotg210); -+ break; -+ case USB_RECIP_INTERFACE: -+ fotg210_set_cxdone(fotg210); -+ break; -+ case USB_RECIP_ENDPOINT: { -+ u8 epnum; -+ epnum = le16_to_cpu(ctrl->wIndex) & USB_ENDPOINT_NUMBER_MASK; -+ if (epnum) -+ fotg210_set_epnstall(fotg210->ep[epnum]); -+ else -+ fotg210_set_cxstall(fotg210); -+ fotg210_set_cxdone(fotg210); -+ } -+ break; -+ default: -+ fotg210_request_error(fotg210); -+ break; -+ } -+} -+ -+static void fotg210_clear_feature(struct fotg210_udc *fotg210, -+ struct usb_ctrlrequest *ctrl) -+{ -+ struct fotg210_ep *ep = -+ fotg210->ep[ctrl->wIndex & USB_ENDPOINT_NUMBER_MASK]; -+ -+ switch (ctrl->bRequestType & USB_RECIP_MASK) { -+ case USB_RECIP_DEVICE: -+ fotg210_set_cxdone(fotg210); -+ break; -+ case USB_RECIP_INTERFACE: -+ fotg210_set_cxdone(fotg210); -+ break; -+ case USB_RECIP_ENDPOINT: -+ if (ctrl->wIndex & USB_ENDPOINT_NUMBER_MASK) { -+ if (ep->wedged) { -+ fotg210_set_cxdone(fotg210); -+ break; -+ } -+ if (ep->stall) -+ fotg210_set_halt_and_wedge(&ep->ep, 0, 0); -+ } -+ fotg210_set_cxdone(fotg210); -+ break; -+ default: -+ fotg210_request_error(fotg210); -+ break; -+ } -+} -+ -+static int fotg210_is_epnstall(struct fotg210_ep *ep) -+{ -+ struct fotg210_udc *fotg210 = ep->fotg210; -+ u32 value; -+ void __iomem *reg; -+ -+ reg = (ep->dir_in) ? -+ fotg210->reg + FOTG210_INEPMPSR(ep->epnum) : -+ fotg210->reg + FOTG210_OUTEPMPSR(ep->epnum); -+ value = ioread32(reg); -+ return value & INOUTEPMPSR_STL_EP ? 1 : 0; -+} -+ -+/* For EP0 requests triggered by this driver (currently GET_STATUS response) */ -+static void fotg210_ep0_complete(struct usb_ep *_ep, struct usb_request *req) -+{ -+ struct fotg210_ep *ep; -+ struct fotg210_udc *fotg210; -+ -+ ep = container_of(_ep, struct fotg210_ep, ep); -+ fotg210 = ep->fotg210; -+ -+ if (req->status || req->actual != req->length) { -+ dev_warn(&fotg210->gadget.dev, "EP0 request failed: %d\n", req->status); -+ } -+} -+ -+static void fotg210_get_status(struct fotg210_udc *fotg210, -+ struct usb_ctrlrequest *ctrl) -+{ -+ u8 epnum; -+ -+ switch (ctrl->bRequestType & USB_RECIP_MASK) { -+ case USB_RECIP_DEVICE: -+ fotg210->ep0_data = cpu_to_le16(1 << USB_DEVICE_SELF_POWERED); -+ break; -+ case USB_RECIP_INTERFACE: -+ fotg210->ep0_data = cpu_to_le16(0); -+ break; -+ case USB_RECIP_ENDPOINT: -+ epnum = ctrl->wIndex & USB_ENDPOINT_NUMBER_MASK; -+ if (epnum) -+ fotg210->ep0_data = -+ cpu_to_le16(fotg210_is_epnstall(fotg210->ep[epnum]) -+ << USB_ENDPOINT_HALT); -+ else -+ fotg210_request_error(fotg210); -+ break; -+ -+ default: -+ fotg210_request_error(fotg210); -+ return; /* exit */ -+ } -+ -+ fotg210->ep0_req->buf = &fotg210->ep0_data; -+ fotg210->ep0_req->length = 2; -+ -+ spin_unlock(&fotg210->lock); -+ fotg210_ep_queue(fotg210->gadget.ep0, fotg210->ep0_req, GFP_ATOMIC); -+ spin_lock(&fotg210->lock); -+} -+ -+static int fotg210_setup_packet(struct fotg210_udc *fotg210, -+ struct usb_ctrlrequest *ctrl) -+{ -+ u8 *p = (u8 *)ctrl; -+ u8 ret = 0; -+ -+ fotg210_rdsetupp(fotg210, p); -+ -+ fotg210->ep[0]->dir_in = ctrl->bRequestType & USB_DIR_IN; -+ -+ if (fotg210->gadget.speed == USB_SPEED_UNKNOWN) { -+ u32 value = ioread32(fotg210->reg + FOTG210_DMCR); -+ fotg210->gadget.speed = value & DMCR_HS_EN ? -+ USB_SPEED_HIGH : USB_SPEED_FULL; -+ } -+ -+ /* check request */ -+ if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { -+ switch (ctrl->bRequest) { -+ case USB_REQ_GET_STATUS: -+ fotg210_get_status(fotg210, ctrl); -+ break; -+ case USB_REQ_CLEAR_FEATURE: -+ fotg210_clear_feature(fotg210, ctrl); -+ break; -+ case USB_REQ_SET_FEATURE: -+ fotg210_set_feature(fotg210, ctrl); -+ break; -+ case USB_REQ_SET_ADDRESS: -+ fotg210_set_address(fotg210, ctrl); -+ break; -+ case USB_REQ_SET_CONFIGURATION: -+ fotg210_set_configuration(fotg210); -+ ret = 1; -+ break; -+ default: -+ ret = 1; -+ break; -+ } -+ } else { -+ ret = 1; -+ } -+ -+ return ret; -+} -+ -+static void fotg210_ep0out(struct fotg210_udc *fotg210) -+{ -+ struct fotg210_ep *ep = fotg210->ep[0]; -+ -+ if (!list_empty(&ep->queue) && !ep->dir_in) { -+ struct fotg210_request *req; -+ -+ req = list_first_entry(&ep->queue, -+ struct fotg210_request, queue); -+ -+ if (req->req.length) -+ fotg210_start_dma(ep, req); -+ -+ if ((req->req.length - req->req.actual) < ep->ep.maxpacket) -+ fotg210_done(ep, req, 0); -+ } else { -+ pr_err("%s : empty queue\n", __func__); -+ } -+} -+ -+static void fotg210_ep0in(struct fotg210_udc *fotg210) -+{ -+ struct fotg210_ep *ep = fotg210->ep[0]; -+ -+ if ((!list_empty(&ep->queue)) && (ep->dir_in)) { -+ struct fotg210_request *req; -+ -+ req = list_entry(ep->queue.next, -+ struct fotg210_request, queue); -+ -+ if (req->req.length) -+ fotg210_start_dma(ep, req); -+ -+ if (req->req.actual == req->req.length) -+ fotg210_done(ep, req, 0); -+ } else { -+ fotg210_set_cxdone(fotg210); -+ } -+} -+ -+static void fotg210_clear_comabt_int(struct fotg210_udc *fotg210) -+{ -+ u32 value = ioread32(fotg210->reg + FOTG210_DISGR0); -+ -+ value &= ~DISGR0_CX_COMABT_INT; -+ iowrite32(value, fotg210->reg + FOTG210_DISGR0); -+} -+ -+static void fotg210_in_fifo_handler(struct fotg210_ep *ep) -+{ -+ struct fotg210_request *req = list_entry(ep->queue.next, -+ struct fotg210_request, queue); -+ -+ if (req->req.length) -+ fotg210_start_dma(ep, req); -+ fotg210_done(ep, req, 0); -+} -+ -+static void fotg210_out_fifo_handler(struct fotg210_ep *ep) -+{ -+ struct fotg210_request *req = list_entry(ep->queue.next, -+ struct fotg210_request, queue); -+ int disgr1 = ioread32(ep->fotg210->reg + FOTG210_DISGR1); -+ -+ fotg210_start_dma(ep, req); -+ -+ /* Complete the request when it's full or a short packet arrived. -+ * Like other drivers, short_not_ok isn't handled. -+ */ -+ -+ if (req->req.length == req->req.actual || -+ (disgr1 & DISGR1_SPK_INT(ep->epnum - 1))) -+ fotg210_done(ep, req, 0); -+} -+ -+static irqreturn_t fotg210_irq(int irq, void *_fotg210) -+{ -+ struct fotg210_udc *fotg210 = _fotg210; -+ u32 int_grp = ioread32(fotg210->reg + FOTG210_DIGR); -+ u32 int_msk = ioread32(fotg210->reg + FOTG210_DMIGR); -+ -+ int_grp &= ~int_msk; -+ -+ spin_lock(&fotg210->lock); -+ -+ if (int_grp & DIGR_INT_G2) { -+ void __iomem *reg = fotg210->reg + FOTG210_DISGR2; -+ u32 int_grp2 = ioread32(reg); -+ u32 int_msk2 = ioread32(fotg210->reg + FOTG210_DMISGR2); -+ u32 value; -+ -+ int_grp2 &= ~int_msk2; -+ -+ if (int_grp2 & DISGR2_USBRST_INT) { -+ usb_gadget_udc_reset(&fotg210->gadget, -+ fotg210->driver); -+ value = ioread32(reg); -+ value &= ~DISGR2_USBRST_INT; -+ iowrite32(value, reg); -+ pr_info("fotg210 udc reset\n"); -+ } -+ if (int_grp2 & DISGR2_SUSP_INT) { -+ value = ioread32(reg); -+ value &= ~DISGR2_SUSP_INT; -+ iowrite32(value, reg); -+ pr_info("fotg210 udc suspend\n"); -+ } -+ if (int_grp2 & DISGR2_RESM_INT) { -+ value = ioread32(reg); -+ value &= ~DISGR2_RESM_INT; -+ iowrite32(value, reg); -+ pr_info("fotg210 udc resume\n"); -+ } -+ if (int_grp2 & DISGR2_ISO_SEQ_ERR_INT) { -+ value = ioread32(reg); -+ value &= ~DISGR2_ISO_SEQ_ERR_INT; -+ iowrite32(value, reg); -+ pr_info("fotg210 iso sequence error\n"); -+ } -+ if (int_grp2 & DISGR2_ISO_SEQ_ABORT_INT) { -+ value = ioread32(reg); -+ value &= ~DISGR2_ISO_SEQ_ABORT_INT; -+ iowrite32(value, reg); -+ pr_info("fotg210 iso sequence abort\n"); -+ } -+ if (int_grp2 & DISGR2_TX0BYTE_INT) { -+ fotg210_clear_tx0byte(fotg210); -+ value = ioread32(reg); -+ value &= ~DISGR2_TX0BYTE_INT; -+ iowrite32(value, reg); -+ pr_info("fotg210 transferred 0 byte\n"); -+ } -+ if (int_grp2 & DISGR2_RX0BYTE_INT) { -+ fotg210_clear_rx0byte(fotg210); -+ value = ioread32(reg); -+ value &= ~DISGR2_RX0BYTE_INT; -+ iowrite32(value, reg); -+ pr_info("fotg210 received 0 byte\n"); -+ } -+ if (int_grp2 & DISGR2_DMA_ERROR) { -+ value = ioread32(reg); -+ value &= ~DISGR2_DMA_ERROR; -+ iowrite32(value, reg); -+ } -+ } -+ -+ if (int_grp & DIGR_INT_G0) { -+ void __iomem *reg = fotg210->reg + FOTG210_DISGR0; -+ u32 int_grp0 = ioread32(reg); -+ u32 int_msk0 = ioread32(fotg210->reg + FOTG210_DMISGR0); -+ struct usb_ctrlrequest ctrl; -+ -+ int_grp0 &= ~int_msk0; -+ -+ /* the highest priority in this source register */ -+ if (int_grp0 & DISGR0_CX_COMABT_INT) { -+ fotg210_clear_comabt_int(fotg210); -+ pr_info("fotg210 CX command abort\n"); -+ } -+ -+ if (int_grp0 & DISGR0_CX_SETUP_INT) { -+ if (fotg210_setup_packet(fotg210, &ctrl)) { -+ spin_unlock(&fotg210->lock); -+ if (fotg210->driver->setup(&fotg210->gadget, -+ &ctrl) < 0) -+ fotg210_set_cxstall(fotg210); -+ spin_lock(&fotg210->lock); -+ } -+ } -+ if (int_grp0 & DISGR0_CX_COMEND_INT) -+ pr_info("fotg210 cmd end\n"); -+ -+ if (int_grp0 & DISGR0_CX_IN_INT) -+ fotg210_ep0in(fotg210); -+ -+ if (int_grp0 & DISGR0_CX_OUT_INT) -+ fotg210_ep0out(fotg210); -+ -+ if (int_grp0 & DISGR0_CX_COMFAIL_INT) { -+ fotg210_set_cxstall(fotg210); -+ pr_info("fotg210 ep0 fail\n"); -+ } -+ } -+ -+ if (int_grp & DIGR_INT_G1) { -+ void __iomem *reg = fotg210->reg + FOTG210_DISGR1; -+ u32 int_grp1 = ioread32(reg); -+ u32 int_msk1 = ioread32(fotg210->reg + FOTG210_DMISGR1); -+ int fifo; -+ -+ int_grp1 &= ~int_msk1; -+ -+ for (fifo = 0; fifo < FOTG210_MAX_FIFO_NUM; fifo++) { -+ if (int_grp1 & DISGR1_IN_INT(fifo)) -+ fotg210_in_fifo_handler(fotg210->ep[fifo + 1]); -+ -+ if ((int_grp1 & DISGR1_OUT_INT(fifo)) || -+ (int_grp1 & DISGR1_SPK_INT(fifo))) -+ fotg210_out_fifo_handler(fotg210->ep[fifo + 1]); -+ } -+ } -+ -+ spin_unlock(&fotg210->lock); -+ -+ return IRQ_HANDLED; -+} -+ -+static void fotg210_disable_unplug(struct fotg210_udc *fotg210) -+{ -+ u32 reg = ioread32(fotg210->reg + FOTG210_PHYTMSR); -+ -+ reg &= ~PHYTMSR_UNPLUG; -+ iowrite32(reg, fotg210->reg + FOTG210_PHYTMSR); -+} -+ -+static int fotg210_udc_start(struct usb_gadget *g, -+ struct usb_gadget_driver *driver) -+{ -+ struct fotg210_udc *fotg210 = gadget_to_fotg210(g); -+ u32 value; -+ -+ /* hook up the driver */ -+ fotg210->driver = driver; -+ -+ /* enable device global interrupt */ -+ value = ioread32(fotg210->reg + FOTG210_DMCR); -+ value |= DMCR_GLINT_EN; -+ iowrite32(value, fotg210->reg + FOTG210_DMCR); -+ -+ return 0; -+} -+ -+static void fotg210_init(struct fotg210_udc *fotg210) -+{ -+ u32 value; -+ -+ /* disable global interrupt and set int polarity to active high */ -+ iowrite32(GMIR_MHC_INT | GMIR_MOTG_INT | GMIR_INT_POLARITY, -+ fotg210->reg + FOTG210_GMIR); -+ -+ /* disable device global interrupt */ -+ value = ioread32(fotg210->reg + FOTG210_DMCR); -+ value &= ~DMCR_GLINT_EN; -+ iowrite32(value, fotg210->reg + FOTG210_DMCR); -+ -+ /* enable only grp2 irqs we handle */ -+ iowrite32(~(DISGR2_DMA_ERROR | DISGR2_RX0BYTE_INT | DISGR2_TX0BYTE_INT -+ | DISGR2_ISO_SEQ_ABORT_INT | DISGR2_ISO_SEQ_ERR_INT -+ | DISGR2_RESM_INT | DISGR2_SUSP_INT | DISGR2_USBRST_INT), -+ fotg210->reg + FOTG210_DMISGR2); -+ -+ /* disable all fifo interrupt */ -+ iowrite32(~(u32)0, fotg210->reg + FOTG210_DMISGR1); -+ -+ /* disable cmd end */ -+ value = ioread32(fotg210->reg + FOTG210_DMISGR0); -+ value |= DMISGR0_MCX_COMEND; -+ iowrite32(value, fotg210->reg + FOTG210_DMISGR0); -+} -+ -+static int fotg210_udc_stop(struct usb_gadget *g) -+{ -+ struct fotg210_udc *fotg210 = gadget_to_fotg210(g); -+ unsigned long flags; -+ -+ spin_lock_irqsave(&fotg210->lock, flags); -+ -+ fotg210_init(fotg210); -+ fotg210->driver = NULL; -+ -+ spin_unlock_irqrestore(&fotg210->lock, flags); -+ -+ return 0; -+} -+ -+static const struct usb_gadget_ops fotg210_gadget_ops = { -+ .udc_start = fotg210_udc_start, -+ .udc_stop = fotg210_udc_stop, -+}; -+ -+static int fotg210_udc_remove(struct platform_device *pdev) -+{ -+ struct fotg210_udc *fotg210 = platform_get_drvdata(pdev); -+ int i; -+ -+ usb_del_gadget_udc(&fotg210->gadget); -+ iounmap(fotg210->reg); -+ free_irq(platform_get_irq(pdev, 0), fotg210); -+ -+ fotg210_ep_free_request(&fotg210->ep[0]->ep, fotg210->ep0_req); -+ for (i = 0; i < FOTG210_MAX_NUM_EP; i++) -+ kfree(fotg210->ep[i]); -+ kfree(fotg210); -+ -+ return 0; -+} -+ -+static int fotg210_udc_probe(struct platform_device *pdev) -+{ -+ struct resource *res, *ires; -+ struct fotg210_udc *fotg210 = NULL; -+ struct fotg210_ep *_ep[FOTG210_MAX_NUM_EP]; -+ int ret = 0; -+ int i; -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (!res) { -+ pr_err("platform_get_resource error.\n"); -+ return -ENODEV; -+ } -+ -+ ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0); -+ if (!ires) { -+ pr_err("platform_get_resource IORESOURCE_IRQ error.\n"); -+ return -ENODEV; -+ } -+ -+ ret = -ENOMEM; -+ -+ /* initialize udc */ -+ fotg210 = kzalloc(sizeof(struct fotg210_udc), GFP_KERNEL); -+ if (fotg210 == NULL) -+ goto err; -+ -+ for (i = 0; i < FOTG210_MAX_NUM_EP; i++) { -+ _ep[i] = kzalloc(sizeof(struct fotg210_ep), GFP_KERNEL); -+ if (_ep[i] == NULL) -+ goto err_alloc; -+ fotg210->ep[i] = _ep[i]; -+ } -+ -+ fotg210->reg = ioremap(res->start, resource_size(res)); -+ if (fotg210->reg == NULL) { -+ pr_err("ioremap error.\n"); -+ goto err_alloc; -+ } -+ -+ spin_lock_init(&fotg210->lock); -+ -+ platform_set_drvdata(pdev, fotg210); -+ -+ fotg210->gadget.ops = &fotg210_gadget_ops; -+ -+ fotg210->gadget.max_speed = USB_SPEED_HIGH; -+ fotg210->gadget.dev.parent = &pdev->dev; -+ fotg210->gadget.dev.dma_mask = pdev->dev.dma_mask; -+ fotg210->gadget.name = udc_name; -+ -+ INIT_LIST_HEAD(&fotg210->gadget.ep_list); -+ -+ for (i = 0; i < FOTG210_MAX_NUM_EP; i++) { -+ struct fotg210_ep *ep = fotg210->ep[i]; -+ -+ if (i) { -+ INIT_LIST_HEAD(&fotg210->ep[i]->ep.ep_list); -+ list_add_tail(&fotg210->ep[i]->ep.ep_list, -+ &fotg210->gadget.ep_list); -+ } -+ ep->fotg210 = fotg210; -+ INIT_LIST_HEAD(&ep->queue); -+ ep->ep.name = fotg210_ep_name[i]; -+ ep->ep.ops = &fotg210_ep_ops; -+ usb_ep_set_maxpacket_limit(&ep->ep, (unsigned short) ~0); -+ -+ if (i == 0) { -+ ep->ep.caps.type_control = true; -+ } else { -+ ep->ep.caps.type_iso = true; -+ ep->ep.caps.type_bulk = true; -+ ep->ep.caps.type_int = true; -+ } -+ -+ ep->ep.caps.dir_in = true; -+ ep->ep.caps.dir_out = true; -+ } -+ usb_ep_set_maxpacket_limit(&fotg210->ep[0]->ep, 0x40); -+ fotg210->gadget.ep0 = &fotg210->ep[0]->ep; -+ INIT_LIST_HEAD(&fotg210->gadget.ep0->ep_list); -+ -+ fotg210->ep0_req = fotg210_ep_alloc_request(&fotg210->ep[0]->ep, -+ GFP_KERNEL); -+ if (fotg210->ep0_req == NULL) -+ goto err_map; -+ -+ fotg210->ep0_req->complete = fotg210_ep0_complete; -+ -+ fotg210_init(fotg210); -+ -+ fotg210_disable_unplug(fotg210); -+ -+ ret = request_irq(ires->start, fotg210_irq, IRQF_SHARED, -+ udc_name, fotg210); -+ if (ret < 0) { -+ pr_err("request_irq error (%d)\n", ret); -+ goto err_req; -+ } -+ -+ ret = usb_add_gadget_udc(&pdev->dev, &fotg210->gadget); -+ if (ret) -+ goto err_add_udc; -+ -+ dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION); -+ -+ return 0; -+ -+err_add_udc: -+ free_irq(ires->start, fotg210); -+ -+err_req: -+ fotg210_ep_free_request(&fotg210->ep[0]->ep, fotg210->ep0_req); -+ -+err_map: -+ iounmap(fotg210->reg); -+ -+err_alloc: -+ for (i = 0; i < FOTG210_MAX_NUM_EP; i++) -+ kfree(fotg210->ep[i]); -+ kfree(fotg210); -+ -+err: -+ return ret; -+} -+ -+static struct platform_driver fotg210_driver = { -+ .driver = { -+ .name = udc_name, -+ }, -+ .probe = fotg210_udc_probe, -+ .remove = fotg210_udc_remove, -+}; -+ -+module_platform_driver(fotg210_driver); -+ -+MODULE_AUTHOR("Yuan-Hsin Chen, Feng-Hsin Chiang "); -+MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION(DRIVER_DESC); ---- a/drivers/usb/gadget/udc/Kconfig -+++ b/drivers/usb/gadget/udc/Kconfig -@@ -108,17 +108,6 @@ config USB_FUSB300 - help - Faraday usb device controller FUSB300 driver - --config USB_FOTG210_UDC -- depends on HAS_DMA -- tristate "Faraday FOTG210 USB Peripheral Controller" -- help -- Faraday USB2.0 OTG controller which can be configured as -- high speed or full speed USB device. This driver supppors -- Bulk Transfer so far. -- -- Say "y" to link the driver statically, or "m" to build a -- dynamically linked module called "fotg210_udc". -- - config USB_GR_UDC - tristate "Aeroflex Gaisler GRUSBDC USB Peripheral Controller Driver" - depends on HAS_DMA ---- a/drivers/usb/gadget/udc/Makefile -+++ b/drivers/usb/gadget/udc/Makefile -@@ -34,7 +34,6 @@ obj-$(CONFIG_USB_EG20T) += pch_udc.o - obj-$(CONFIG_USB_MV_UDC) += mv_udc.o - mv_udc-y := mv_udc_core.o - obj-$(CONFIG_USB_FUSB300) += fusb300_udc.o --obj-$(CONFIG_USB_FOTG210_UDC) += fotg210-udc.o - obj-$(CONFIG_USB_MV_U3D) += mv_u3d_core.o - obj-$(CONFIG_USB_GR_UDC) += gr_udc.o - obj-$(CONFIG_USB_GADGET_XILINX) += udc-xilinx.o ---- a/drivers/usb/host/Kconfig -+++ b/drivers/usb/host/Kconfig -@@ -389,17 +389,6 @@ config USB_ISP1362_HCD - To compile this driver as a module, choose M here: the - module will be called isp1362-hcd. - --config USB_FOTG210_HCD -- tristate "FOTG210 HCD support" -- depends on USB && HAS_DMA && HAS_IOMEM -- help -- Faraday FOTG210 is an OTG controller which can be configured as -- an USB2.0 host. It is designed to meet USB2.0 EHCI specification -- with minor modification. -- -- To compile this driver as a module, choose M here: the -- module will be called fotg210-hcd. -- - config USB_MAX3421_HCD - tristate "MAX3421 HCD (USB-over-SPI) support" - depends on USB && SPI ---- a/drivers/usb/host/Makefile -+++ b/drivers/usb/host/Makefile -@@ -84,6 +84,5 @@ obj-$(CONFIG_USB_EHCI_FSL) += ehci-fsl.o - obj-$(CONFIG_USB_EHCI_MV) += ehci-mv.o - obj-$(CONFIG_USB_HCD_BCMA) += bcma-hcd.o - obj-$(CONFIG_USB_HCD_SSB) += ssb-hcd.o --obj-$(CONFIG_USB_FOTG210_HCD) += fotg210-hcd.o - obj-$(CONFIG_USB_MAX3421_HCD) += max3421-hcd.o - obj-$(CONFIG_USB_XEN_HCD) += xen-hcd.o ---- /dev/null -+++ b/drivers/usb/fotg210/fotg210-hcd.h -@@ -0,0 +1,688 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+#ifndef __LINUX_FOTG210_H -+#define __LINUX_FOTG210_H -+ -+#include -+ -+/* definitions used for the EHCI driver */ -+ -+/* -+ * __hc32 and __hc16 are "Host Controller" types, they may be equivalent to -+ * __leXX (normally) or __beXX (given FOTG210_BIG_ENDIAN_DESC), depending on -+ * the host controller implementation. -+ * -+ * To facilitate the strongest possible byte-order checking from "sparse" -+ * and so on, we use __leXX unless that's not practical. -+ */ -+#define __hc32 __le32 -+#define __hc16 __le16 -+ -+/* statistics can be kept for tuning/monitoring */ -+struct fotg210_stats { -+ /* irq usage */ -+ unsigned long normal; -+ unsigned long error; -+ unsigned long iaa; -+ unsigned long lost_iaa; -+ -+ /* termination of urbs from core */ -+ unsigned long complete; -+ unsigned long unlink; -+}; -+ -+/* fotg210_hcd->lock guards shared data against other CPUs: -+ * fotg210_hcd: async, unlink, periodic (and shadow), ... -+ * usb_host_endpoint: hcpriv -+ * fotg210_qh: qh_next, qtd_list -+ * fotg210_qtd: qtd_list -+ * -+ * Also, hold this lock when talking to HC registers or -+ * when updating hw_* fields in shared qh/qtd/... structures. -+ */ -+ -+#define FOTG210_MAX_ROOT_PORTS 1 /* see HCS_N_PORTS */ -+ -+/* -+ * fotg210_rh_state values of FOTG210_RH_RUNNING or above mean that the -+ * controller may be doing DMA. Lower values mean there's no DMA. -+ */ -+enum fotg210_rh_state { -+ FOTG210_RH_HALTED, -+ FOTG210_RH_SUSPENDED, -+ FOTG210_RH_RUNNING, -+ FOTG210_RH_STOPPING -+}; -+ -+/* -+ * Timer events, ordered by increasing delay length. -+ * Always update event_delays_ns[] and event_handlers[] (defined in -+ * ehci-timer.c) in parallel with this list. -+ */ -+enum fotg210_hrtimer_event { -+ FOTG210_HRTIMER_POLL_ASS, /* Poll for async schedule off */ -+ FOTG210_HRTIMER_POLL_PSS, /* Poll for periodic schedule off */ -+ FOTG210_HRTIMER_POLL_DEAD, /* Wait for dead controller to stop */ -+ FOTG210_HRTIMER_UNLINK_INTR, /* Wait for interrupt QH unlink */ -+ FOTG210_HRTIMER_FREE_ITDS, /* Wait for unused iTDs and siTDs */ -+ FOTG210_HRTIMER_ASYNC_UNLINKS, /* Unlink empty async QHs */ -+ FOTG210_HRTIMER_IAA_WATCHDOG, /* Handle lost IAA interrupts */ -+ FOTG210_HRTIMER_DISABLE_PERIODIC, /* Wait to disable periodic sched */ -+ FOTG210_HRTIMER_DISABLE_ASYNC, /* Wait to disable async sched */ -+ FOTG210_HRTIMER_IO_WATCHDOG, /* Check for missing IRQs */ -+ FOTG210_HRTIMER_NUM_EVENTS /* Must come last */ -+}; -+#define FOTG210_HRTIMER_NO_EVENT 99 -+ -+struct fotg210_hcd { /* one per controller */ -+ /* timing support */ -+ enum fotg210_hrtimer_event next_hrtimer_event; -+ unsigned enabled_hrtimer_events; -+ ktime_t hr_timeouts[FOTG210_HRTIMER_NUM_EVENTS]; -+ struct hrtimer hrtimer; -+ -+ int PSS_poll_count; -+ int ASS_poll_count; -+ int died_poll_count; -+ -+ /* glue to PCI and HCD framework */ -+ struct fotg210_caps __iomem *caps; -+ struct fotg210_regs __iomem *regs; -+ struct ehci_dbg_port __iomem *debug; -+ -+ __u32 hcs_params; /* cached register copy */ -+ spinlock_t lock; -+ enum fotg210_rh_state rh_state; -+ -+ /* general schedule support */ -+ bool scanning:1; -+ bool need_rescan:1; -+ bool intr_unlinking:1; -+ bool async_unlinking:1; -+ bool shutdown:1; -+ struct fotg210_qh *qh_scan_next; -+ -+ /* async schedule support */ -+ struct fotg210_qh *async; -+ struct fotg210_qh *dummy; /* For AMD quirk use */ -+ struct fotg210_qh *async_unlink; -+ struct fotg210_qh *async_unlink_last; -+ struct fotg210_qh *async_iaa; -+ unsigned async_unlink_cycle; -+ unsigned async_count; /* async activity count */ -+ -+ /* periodic schedule support */ -+#define DEFAULT_I_TDPS 1024 /* some HCs can do less */ -+ unsigned periodic_size; -+ __hc32 *periodic; /* hw periodic table */ -+ dma_addr_t periodic_dma; -+ struct list_head intr_qh_list; -+ unsigned i_thresh; /* uframes HC might cache */ -+ -+ union fotg210_shadow *pshadow; /* mirror hw periodic table */ -+ struct fotg210_qh *intr_unlink; -+ struct fotg210_qh *intr_unlink_last; -+ unsigned intr_unlink_cycle; -+ unsigned now_frame; /* frame from HC hardware */ -+ unsigned next_frame; /* scan periodic, start here */ -+ unsigned intr_count; /* intr activity count */ -+ unsigned isoc_count; /* isoc activity count */ -+ unsigned periodic_count; /* periodic activity count */ -+ /* max periodic time per uframe */ -+ unsigned uframe_periodic_max; -+ -+ -+ /* list of itds completed while now_frame was still active */ -+ struct list_head cached_itd_list; -+ struct fotg210_itd *last_itd_to_free; -+ -+ /* per root hub port */ -+ unsigned long reset_done[FOTG210_MAX_ROOT_PORTS]; -+ -+ /* bit vectors (one bit per port) -+ * which ports were already suspended at the start of a bus suspend -+ */ -+ unsigned long bus_suspended; -+ -+ /* which ports are edicated to the companion controller */ -+ unsigned long companion_ports; -+ -+ /* which ports are owned by the companion during a bus suspend */ -+ unsigned long owned_ports; -+ -+ /* which ports have the change-suspend feature turned on */ -+ unsigned long port_c_suspend; -+ -+ /* which ports are suspended */ -+ unsigned long suspended_ports; -+ -+ /* which ports have started to resume */ -+ unsigned long resuming_ports; -+ -+ /* per-HC memory pools (could be per-bus, but ...) */ -+ struct dma_pool *qh_pool; /* qh per active urb */ -+ struct dma_pool *qtd_pool; /* one or more per qh */ -+ struct dma_pool *itd_pool; /* itd per iso urb */ -+ -+ unsigned random_frame; -+ unsigned long next_statechange; -+ ktime_t last_periodic_enable; -+ u32 command; -+ -+ /* SILICON QUIRKS */ -+ unsigned need_io_watchdog:1; -+ unsigned fs_i_thresh:1; /* Intel iso scheduling */ -+ -+ u8 sbrn; /* packed release number */ -+ -+ /* irq statistics */ -+#ifdef FOTG210_STATS -+ struct fotg210_stats stats; -+# define INCR(x) ((x)++) -+#else -+# define INCR(x) do {} while (0) -+#endif -+ -+ /* silicon clock */ -+ struct clk *pclk; -+}; -+ -+/* convert between an HCD pointer and the corresponding FOTG210_HCD */ -+static inline struct fotg210_hcd *hcd_to_fotg210(struct usb_hcd *hcd) -+{ -+ return (struct fotg210_hcd *)(hcd->hcd_priv); -+} -+static inline struct usb_hcd *fotg210_to_hcd(struct fotg210_hcd *fotg210) -+{ -+ return container_of((void *) fotg210, struct usb_hcd, hcd_priv); -+} -+ -+/*-------------------------------------------------------------------------*/ -+ -+/* EHCI register interface, corresponds to EHCI Revision 0.95 specification */ -+ -+/* Section 2.2 Host Controller Capability Registers */ -+struct fotg210_caps { -+ /* these fields are specified as 8 and 16 bit registers, -+ * but some hosts can't perform 8 or 16 bit PCI accesses. -+ * some hosts treat caplength and hciversion as parts of a 32-bit -+ * register, others treat them as two separate registers, this -+ * affects the memory map for big endian controllers. -+ */ -+ u32 hc_capbase; -+#define HC_LENGTH(fotg210, p) (0x00ff&((p) >> /* bits 7:0 / offset 00h */ \ -+ (fotg210_big_endian_capbase(fotg210) ? 24 : 0))) -+#define HC_VERSION(fotg210, p) (0xffff&((p) >> /* bits 31:16 / offset 02h */ \ -+ (fotg210_big_endian_capbase(fotg210) ? 0 : 16))) -+ u32 hcs_params; /* HCSPARAMS - offset 0x4 */ -+#define HCS_N_PORTS(p) (((p)>>0)&0xf) /* bits 3:0, ports on HC */ -+ -+ u32 hcc_params; /* HCCPARAMS - offset 0x8 */ -+#define HCC_CANPARK(p) ((p)&(1 << 2)) /* true: can park on async qh */ -+#define HCC_PGM_FRAMELISTLEN(p) ((p)&(1 << 1)) /* true: periodic_size changes*/ -+ u8 portroute[8]; /* nibbles for routing - offset 0xC */ -+}; -+ -+ -+/* Section 2.3 Host Controller Operational Registers */ -+struct fotg210_regs { -+ -+ /* USBCMD: offset 0x00 */ -+ u32 command; -+ -+/* EHCI 1.1 addendum */ -+/* 23:16 is r/w intr rate, in microframes; default "8" == 1/msec */ -+#define CMD_PARK (1<<11) /* enable "park" on async qh */ -+#define CMD_PARK_CNT(c) (((c)>>8)&3) /* how many transfers to park for */ -+#define CMD_IAAD (1<<6) /* "doorbell" interrupt async advance */ -+#define CMD_ASE (1<<5) /* async schedule enable */ -+#define CMD_PSE (1<<4) /* periodic schedule enable */ -+/* 3:2 is periodic frame list size */ -+#define CMD_RESET (1<<1) /* reset HC not bus */ -+#define CMD_RUN (1<<0) /* start/stop HC */ -+ -+ /* USBSTS: offset 0x04 */ -+ u32 status; -+#define STS_ASS (1<<15) /* Async Schedule Status */ -+#define STS_PSS (1<<14) /* Periodic Schedule Status */ -+#define STS_RECL (1<<13) /* Reclamation */ -+#define STS_HALT (1<<12) /* Not running (any reason) */ -+/* some bits reserved */ -+ /* these STS_* flags are also intr_enable bits (USBINTR) */ -+#define STS_IAA (1<<5) /* Interrupted on async advance */ -+#define STS_FATAL (1<<4) /* such as some PCI access errors */ -+#define STS_FLR (1<<3) /* frame list rolled over */ -+#define STS_PCD (1<<2) /* port change detect */ -+#define STS_ERR (1<<1) /* "error" completion (overflow, ...) */ -+#define STS_INT (1<<0) /* "normal" completion (short, ...) */ -+ -+ /* USBINTR: offset 0x08 */ -+ u32 intr_enable; -+ -+ /* FRINDEX: offset 0x0C */ -+ u32 frame_index; /* current microframe number */ -+ /* CTRLDSSEGMENT: offset 0x10 */ -+ u32 segment; /* address bits 63:32 if needed */ -+ /* PERIODICLISTBASE: offset 0x14 */ -+ u32 frame_list; /* points to periodic list */ -+ /* ASYNCLISTADDR: offset 0x18 */ -+ u32 async_next; /* address of next async queue head */ -+ -+ u32 reserved1; -+ /* PORTSC: offset 0x20 */ -+ u32 port_status; -+/* 31:23 reserved */ -+#define PORT_USB11(x) (((x)&(3<<10)) == (1<<10)) /* USB 1.1 device */ -+#define PORT_RESET (1<<8) /* reset port */ -+#define PORT_SUSPEND (1<<7) /* suspend port */ -+#define PORT_RESUME (1<<6) /* resume it */ -+#define PORT_PEC (1<<3) /* port enable change */ -+#define PORT_PE (1<<2) /* port enable */ -+#define PORT_CSC (1<<1) /* connect status change */ -+#define PORT_CONNECT (1<<0) /* device connected */ -+#define PORT_RWC_BITS (PORT_CSC | PORT_PEC) -+ u32 reserved2[19]; -+ -+ /* OTGCSR: offet 0x70 */ -+ u32 otgcsr; -+#define OTGCSR_HOST_SPD_TYP (3 << 22) -+#define OTGCSR_A_BUS_DROP (1 << 5) -+#define OTGCSR_A_BUS_REQ (1 << 4) -+ -+ /* OTGISR: offset 0x74 */ -+ u32 otgisr; -+#define OTGISR_OVC (1 << 10) -+ -+ u32 reserved3[15]; -+ -+ /* GMIR: offset 0xB4 */ -+ u32 gmir; -+#define GMIR_INT_POLARITY (1 << 3) /*Active High*/ -+#define GMIR_MHC_INT (1 << 2) -+#define GMIR_MOTG_INT (1 << 1) -+#define GMIR_MDEV_INT (1 << 0) -+}; -+ -+/*-------------------------------------------------------------------------*/ -+ -+#define QTD_NEXT(fotg210, dma) cpu_to_hc32(fotg210, (u32)dma) -+ -+/* -+ * EHCI Specification 0.95 Section 3.5 -+ * QTD: describe data transfer components (buffer, direction, ...) -+ * See Fig 3-6 "Queue Element Transfer Descriptor Block Diagram". -+ * -+ * These are associated only with "QH" (Queue Head) structures, -+ * used with control, bulk, and interrupt transfers. -+ */ -+struct fotg210_qtd { -+ /* first part defined by EHCI spec */ -+ __hc32 hw_next; /* see EHCI 3.5.1 */ -+ __hc32 hw_alt_next; /* see EHCI 3.5.2 */ -+ __hc32 hw_token; /* see EHCI 3.5.3 */ -+#define QTD_TOGGLE (1 << 31) /* data toggle */ -+#define QTD_LENGTH(tok) (((tok)>>16) & 0x7fff) -+#define QTD_IOC (1 << 15) /* interrupt on complete */ -+#define QTD_CERR(tok) (((tok)>>10) & 0x3) -+#define QTD_PID(tok) (((tok)>>8) & 0x3) -+#define QTD_STS_ACTIVE (1 << 7) /* HC may execute this */ -+#define QTD_STS_HALT (1 << 6) /* halted on error */ -+#define QTD_STS_DBE (1 << 5) /* data buffer error (in HC) */ -+#define QTD_STS_BABBLE (1 << 4) /* device was babbling (qtd halted) */ -+#define QTD_STS_XACT (1 << 3) /* device gave illegal response */ -+#define QTD_STS_MMF (1 << 2) /* incomplete split transaction */ -+#define QTD_STS_STS (1 << 1) /* split transaction state */ -+#define QTD_STS_PING (1 << 0) /* issue PING? */ -+ -+#define ACTIVE_BIT(fotg210) cpu_to_hc32(fotg210, QTD_STS_ACTIVE) -+#define HALT_BIT(fotg210) cpu_to_hc32(fotg210, QTD_STS_HALT) -+#define STATUS_BIT(fotg210) cpu_to_hc32(fotg210, QTD_STS_STS) -+ -+ __hc32 hw_buf[5]; /* see EHCI 3.5.4 */ -+ __hc32 hw_buf_hi[5]; /* Appendix B */ -+ -+ /* the rest is HCD-private */ -+ dma_addr_t qtd_dma; /* qtd address */ -+ struct list_head qtd_list; /* sw qtd list */ -+ struct urb *urb; /* qtd's urb */ -+ size_t length; /* length of buffer */ -+} __aligned(32); -+ -+/* mask NakCnt+T in qh->hw_alt_next */ -+#define QTD_MASK(fotg210) cpu_to_hc32(fotg210, ~0x1f) -+ -+#define IS_SHORT_READ(token) (QTD_LENGTH(token) != 0 && QTD_PID(token) == 1) -+ -+/*-------------------------------------------------------------------------*/ -+ -+/* type tag from {qh,itd,fstn}->hw_next */ -+#define Q_NEXT_TYPE(fotg210, dma) ((dma) & cpu_to_hc32(fotg210, 3 << 1)) -+ -+/* -+ * Now the following defines are not converted using the -+ * cpu_to_le32() macro anymore, since we have to support -+ * "dynamic" switching between be and le support, so that the driver -+ * can be used on one system with SoC EHCI controller using big-endian -+ * descriptors as well as a normal little-endian PCI EHCI controller. -+ */ -+/* values for that type tag */ -+#define Q_TYPE_ITD (0 << 1) -+#define Q_TYPE_QH (1 << 1) -+#define Q_TYPE_SITD (2 << 1) -+#define Q_TYPE_FSTN (3 << 1) -+ -+/* next async queue entry, or pointer to interrupt/periodic QH */ -+#define QH_NEXT(fotg210, dma) \ -+ (cpu_to_hc32(fotg210, (((u32)dma)&~0x01f)|Q_TYPE_QH)) -+ -+/* for periodic/async schedules and qtd lists, mark end of list */ -+#define FOTG210_LIST_END(fotg210) \ -+ cpu_to_hc32(fotg210, 1) /* "null pointer" to hw */ -+ -+/* -+ * Entries in periodic shadow table are pointers to one of four kinds -+ * of data structure. That's dictated by the hardware; a type tag is -+ * encoded in the low bits of the hardware's periodic schedule. Use -+ * Q_NEXT_TYPE to get the tag. -+ * -+ * For entries in the async schedule, the type tag always says "qh". -+ */ -+union fotg210_shadow { -+ struct fotg210_qh *qh; /* Q_TYPE_QH */ -+ struct fotg210_itd *itd; /* Q_TYPE_ITD */ -+ struct fotg210_fstn *fstn; /* Q_TYPE_FSTN */ -+ __hc32 *hw_next; /* (all types) */ -+ void *ptr; -+}; -+ -+/*-------------------------------------------------------------------------*/ -+ -+/* -+ * EHCI Specification 0.95 Section 3.6 -+ * QH: describes control/bulk/interrupt endpoints -+ * See Fig 3-7 "Queue Head Structure Layout". -+ * -+ * These appear in both the async and (for interrupt) periodic schedules. -+ */ -+ -+/* first part defined by EHCI spec */ -+struct fotg210_qh_hw { -+ __hc32 hw_next; /* see EHCI 3.6.1 */ -+ __hc32 hw_info1; /* see EHCI 3.6.2 */ -+#define QH_CONTROL_EP (1 << 27) /* FS/LS control endpoint */ -+#define QH_HEAD (1 << 15) /* Head of async reclamation list */ -+#define QH_TOGGLE_CTL (1 << 14) /* Data toggle control */ -+#define QH_HIGH_SPEED (2 << 12) /* Endpoint speed */ -+#define QH_LOW_SPEED (1 << 12) -+#define QH_FULL_SPEED (0 << 12) -+#define QH_INACTIVATE (1 << 7) /* Inactivate on next transaction */ -+ __hc32 hw_info2; /* see EHCI 3.6.2 */ -+#define QH_SMASK 0x000000ff -+#define QH_CMASK 0x0000ff00 -+#define QH_HUBADDR 0x007f0000 -+#define QH_HUBPORT 0x3f800000 -+#define QH_MULT 0xc0000000 -+ __hc32 hw_current; /* qtd list - see EHCI 3.6.4 */ -+ -+ /* qtd overlay (hardware parts of a struct fotg210_qtd) */ -+ __hc32 hw_qtd_next; -+ __hc32 hw_alt_next; -+ __hc32 hw_token; -+ __hc32 hw_buf[5]; -+ __hc32 hw_buf_hi[5]; -+} __aligned(32); -+ -+struct fotg210_qh { -+ struct fotg210_qh_hw *hw; /* Must come first */ -+ /* the rest is HCD-private */ -+ dma_addr_t qh_dma; /* address of qh */ -+ union fotg210_shadow qh_next; /* ptr to qh; or periodic */ -+ struct list_head qtd_list; /* sw qtd list */ -+ struct list_head intr_node; /* list of intr QHs */ -+ struct fotg210_qtd *dummy; -+ struct fotg210_qh *unlink_next; /* next on unlink list */ -+ -+ unsigned unlink_cycle; -+ -+ u8 needs_rescan; /* Dequeue during giveback */ -+ u8 qh_state; -+#define QH_STATE_LINKED 1 /* HC sees this */ -+#define QH_STATE_UNLINK 2 /* HC may still see this */ -+#define QH_STATE_IDLE 3 /* HC doesn't see this */ -+#define QH_STATE_UNLINK_WAIT 4 /* LINKED and on unlink q */ -+#define QH_STATE_COMPLETING 5 /* don't touch token.HALT */ -+ -+ u8 xacterrs; /* XactErr retry counter */ -+#define QH_XACTERR_MAX 32 /* XactErr retry limit */ -+ -+ /* periodic schedule info */ -+ u8 usecs; /* intr bandwidth */ -+ u8 gap_uf; /* uframes split/csplit gap */ -+ u8 c_usecs; /* ... split completion bw */ -+ u16 tt_usecs; /* tt downstream bandwidth */ -+ unsigned short period; /* polling interval */ -+ unsigned short start; /* where polling starts */ -+#define NO_FRAME ((unsigned short)~0) /* pick new start */ -+ -+ struct usb_device *dev; /* access to TT */ -+ unsigned is_out:1; /* bulk or intr OUT */ -+ unsigned clearing_tt:1; /* Clear-TT-Buf in progress */ -+}; -+ -+/*-------------------------------------------------------------------------*/ -+ -+/* description of one iso transaction (up to 3 KB data if highspeed) */ -+struct fotg210_iso_packet { -+ /* These will be copied to iTD when scheduling */ -+ u64 bufp; /* itd->hw_bufp{,_hi}[pg] |= */ -+ __hc32 transaction; /* itd->hw_transaction[i] |= */ -+ u8 cross; /* buf crosses pages */ -+ /* for full speed OUT splits */ -+ u32 buf1; -+}; -+ -+/* temporary schedule data for packets from iso urbs (both speeds) -+ * each packet is one logical usb transaction to the device (not TT), -+ * beginning at stream->next_uframe -+ */ -+struct fotg210_iso_sched { -+ struct list_head td_list; -+ unsigned span; -+ struct fotg210_iso_packet packet[]; -+}; -+ -+/* -+ * fotg210_iso_stream - groups all (s)itds for this endpoint. -+ * acts like a qh would, if EHCI had them for ISO. -+ */ -+struct fotg210_iso_stream { -+ /* first field matches fotg210_hq, but is NULL */ -+ struct fotg210_qh_hw *hw; -+ -+ u8 bEndpointAddress; -+ u8 highspeed; -+ struct list_head td_list; /* queued itds */ -+ struct list_head free_list; /* list of unused itds */ -+ struct usb_device *udev; -+ struct usb_host_endpoint *ep; -+ -+ /* output of (re)scheduling */ -+ int next_uframe; -+ __hc32 splits; -+ -+ /* the rest is derived from the endpoint descriptor, -+ * trusting urb->interval == f(epdesc->bInterval) and -+ * including the extra info for hw_bufp[0..2] -+ */ -+ u8 usecs, c_usecs; -+ u16 interval; -+ u16 tt_usecs; -+ u16 maxp; -+ u16 raw_mask; -+ unsigned bandwidth; -+ -+ /* This is used to initialize iTD's hw_bufp fields */ -+ __hc32 buf0; -+ __hc32 buf1; -+ __hc32 buf2; -+ -+ /* this is used to initialize sITD's tt info */ -+ __hc32 address; -+}; -+ -+/*-------------------------------------------------------------------------*/ -+ -+/* -+ * EHCI Specification 0.95 Section 3.3 -+ * Fig 3-4 "Isochronous Transaction Descriptor (iTD)" -+ * -+ * Schedule records for high speed iso xfers -+ */ -+struct fotg210_itd { -+ /* first part defined by EHCI spec */ -+ __hc32 hw_next; /* see EHCI 3.3.1 */ -+ __hc32 hw_transaction[8]; /* see EHCI 3.3.2 */ -+#define FOTG210_ISOC_ACTIVE (1<<31) /* activate transfer this slot */ -+#define FOTG210_ISOC_BUF_ERR (1<<30) /* Data buffer error */ -+#define FOTG210_ISOC_BABBLE (1<<29) /* babble detected */ -+#define FOTG210_ISOC_XACTERR (1<<28) /* XactErr - transaction error */ -+#define FOTG210_ITD_LENGTH(tok) (((tok)>>16) & 0x0fff) -+#define FOTG210_ITD_IOC (1 << 15) /* interrupt on complete */ -+ -+#define ITD_ACTIVE(fotg210) cpu_to_hc32(fotg210, FOTG210_ISOC_ACTIVE) -+ -+ __hc32 hw_bufp[7]; /* see EHCI 3.3.3 */ -+ __hc32 hw_bufp_hi[7]; /* Appendix B */ -+ -+ /* the rest is HCD-private */ -+ dma_addr_t itd_dma; /* for this itd */ -+ union fotg210_shadow itd_next; /* ptr to periodic q entry */ -+ -+ struct urb *urb; -+ struct fotg210_iso_stream *stream; /* endpoint's queue */ -+ struct list_head itd_list; /* list of stream's itds */ -+ -+ /* any/all hw_transactions here may be used by that urb */ -+ unsigned frame; /* where scheduled */ -+ unsigned pg; -+ unsigned index[8]; /* in urb->iso_frame_desc */ -+} __aligned(32); -+ -+/*-------------------------------------------------------------------------*/ -+ -+/* -+ * EHCI Specification 0.96 Section 3.7 -+ * Periodic Frame Span Traversal Node (FSTN) -+ * -+ * Manages split interrupt transactions (using TT) that span frame boundaries -+ * into uframes 0/1; see 4.12.2.2. In those uframes, a "save place" FSTN -+ * makes the HC jump (back) to a QH to scan for fs/ls QH completions until -+ * it hits a "restore" FSTN; then it returns to finish other uframe 0/1 work. -+ */ -+struct fotg210_fstn { -+ __hc32 hw_next; /* any periodic q entry */ -+ __hc32 hw_prev; /* qh or FOTG210_LIST_END */ -+ -+ /* the rest is HCD-private */ -+ dma_addr_t fstn_dma; -+ union fotg210_shadow fstn_next; /* ptr to periodic q entry */ -+} __aligned(32); -+ -+/*-------------------------------------------------------------------------*/ -+ -+/* Prepare the PORTSC wakeup flags during controller suspend/resume */ -+ -+#define fotg210_prepare_ports_for_controller_suspend(fotg210, do_wakeup) \ -+ fotg210_adjust_port_wakeup_flags(fotg210, true, do_wakeup) -+ -+#define fotg210_prepare_ports_for_controller_resume(fotg210) \ -+ fotg210_adjust_port_wakeup_flags(fotg210, false, false) -+ -+/*-------------------------------------------------------------------------*/ -+ -+/* -+ * Some EHCI controllers have a Transaction Translator built into the -+ * root hub. This is a non-standard feature. Each controller will need -+ * to add code to the following inline functions, and call them as -+ * needed (mostly in root hub code). -+ */ -+ -+static inline unsigned int -+fotg210_get_speed(struct fotg210_hcd *fotg210, unsigned int portsc) -+{ -+ return (readl(&fotg210->regs->otgcsr) -+ & OTGCSR_HOST_SPD_TYP) >> 22; -+} -+ -+/* Returns the speed of a device attached to a port on the root hub. */ -+static inline unsigned int -+fotg210_port_speed(struct fotg210_hcd *fotg210, unsigned int portsc) -+{ -+ switch (fotg210_get_speed(fotg210, portsc)) { -+ case 0: -+ return 0; -+ case 1: -+ return USB_PORT_STAT_LOW_SPEED; -+ case 2: -+ default: -+ return USB_PORT_STAT_HIGH_SPEED; -+ } -+} -+ -+/*-------------------------------------------------------------------------*/ -+ -+#define fotg210_has_fsl_portno_bug(e) (0) -+ -+/* -+ * While most USB host controllers implement their registers in -+ * little-endian format, a minority (celleb companion chip) implement -+ * them in big endian format. -+ * -+ * This attempts to support either format at compile time without a -+ * runtime penalty, or both formats with the additional overhead -+ * of checking a flag bit. -+ * -+ */ -+ -+#define fotg210_big_endian_mmio(e) 0 -+#define fotg210_big_endian_capbase(e) 0 -+ -+static inline unsigned int fotg210_readl(const struct fotg210_hcd *fotg210, -+ __u32 __iomem *regs) -+{ -+ return readl(regs); -+} -+ -+static inline void fotg210_writel(const struct fotg210_hcd *fotg210, -+ const unsigned int val, __u32 __iomem *regs) -+{ -+ writel(val, regs); -+} -+ -+/* cpu to fotg210 */ -+static inline __hc32 cpu_to_hc32(const struct fotg210_hcd *fotg210, const u32 x) -+{ -+ return cpu_to_le32(x); -+} -+ -+/* fotg210 to cpu */ -+static inline u32 hc32_to_cpu(const struct fotg210_hcd *fotg210, const __hc32 x) -+{ -+ return le32_to_cpu(x); -+} -+ -+static inline u32 hc32_to_cpup(const struct fotg210_hcd *fotg210, -+ const __hc32 *x) -+{ -+ return le32_to_cpup(x); -+} -+ -+/*-------------------------------------------------------------------------*/ -+ -+static inline unsigned fotg210_read_frame_index(struct fotg210_hcd *fotg210) -+{ -+ return fotg210_readl(fotg210, &fotg210->regs->frame_index); -+} -+ -+/*-------------------------------------------------------------------------*/ -+ -+#endif /* __LINUX_FOTG210_H */ ---- /dev/null -+++ b/drivers/usb/fotg210/fotg210-udc.h -@@ -0,0 +1,249 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Faraday FOTG210 USB OTG controller -+ * -+ * Copyright (C) 2013 Faraday Technology Corporation -+ * Author: Yuan-Hsin Chen -+ */ -+ -+#include -+ -+#define FOTG210_MAX_NUM_EP 5 /* ep0...ep4 */ -+#define FOTG210_MAX_FIFO_NUM 4 /* fifo0...fifo4 */ -+ -+/* Global Mask of HC/OTG/DEV interrupt Register(0xC4) */ -+#define FOTG210_GMIR 0xC4 -+#define GMIR_INT_POLARITY 0x8 /*Active High*/ -+#define GMIR_MHC_INT 0x4 -+#define GMIR_MOTG_INT 0x2 -+#define GMIR_MDEV_INT 0x1 -+ -+/* Device Main Control Register(0x100) */ -+#define FOTG210_DMCR 0x100 -+#define DMCR_HS_EN (1 << 6) -+#define DMCR_CHIP_EN (1 << 5) -+#define DMCR_SFRST (1 << 4) -+#define DMCR_GOSUSP (1 << 3) -+#define DMCR_GLINT_EN (1 << 2) -+#define DMCR_HALF_SPEED (1 << 1) -+#define DMCR_CAP_RMWAKUP (1 << 0) -+ -+/* Device Address Register(0x104) */ -+#define FOTG210_DAR 0x104 -+#define DAR_AFT_CONF (1 << 7) -+ -+/* Device Test Register(0x108) */ -+#define FOTG210_DTR 0x108 -+#define DTR_TST_CLRFF (1 << 0) -+ -+/* PHY Test Mode Selector register(0x114) */ -+#define FOTG210_PHYTMSR 0x114 -+#define PHYTMSR_TST_PKT (1 << 4) -+#define PHYTMSR_TST_SE0NAK (1 << 3) -+#define PHYTMSR_TST_KSTA (1 << 2) -+#define PHYTMSR_TST_JSTA (1 << 1) -+#define PHYTMSR_UNPLUG (1 << 0) -+ -+/* Cx configuration and FIFO Empty Status register(0x120) */ -+#define FOTG210_DCFESR 0x120 -+#define DCFESR_FIFO_EMPTY(fifo) (1 << 8 << (fifo)) -+#define DCFESR_CX_EMP (1 << 5) -+#define DCFESR_CX_CLR (1 << 3) -+#define DCFESR_CX_STL (1 << 2) -+#define DCFESR_TST_PKDONE (1 << 1) -+#define DCFESR_CX_DONE (1 << 0) -+ -+/* Device IDLE Counter Register(0x124) */ -+#define FOTG210_DICR 0x124 -+ -+/* Device Mask of Interrupt Group Register (0x130) */ -+#define FOTG210_DMIGR 0x130 -+#define DMIGR_MINT_G0 (1 << 0) -+ -+/* Device Mask of Interrupt Source Group 0(0x134) */ -+#define FOTG210_DMISGR0 0x134 -+#define DMISGR0_MCX_COMEND (1 << 3) -+#define DMISGR0_MCX_OUT_INT (1 << 2) -+#define DMISGR0_MCX_IN_INT (1 << 1) -+#define DMISGR0_MCX_SETUP_INT (1 << 0) -+ -+/* Device Mask of Interrupt Source Group 1 Register(0x138)*/ -+#define FOTG210_DMISGR1 0x138 -+#define DMISGR1_MF3_IN_INT (1 << 19) -+#define DMISGR1_MF2_IN_INT (1 << 18) -+#define DMISGR1_MF1_IN_INT (1 << 17) -+#define DMISGR1_MF0_IN_INT (1 << 16) -+#define DMISGR1_MF_IN_INT(fifo) (1 << (16 + (fifo))) -+#define DMISGR1_MF3_SPK_INT (1 << 7) -+#define DMISGR1_MF3_OUT_INT (1 << 6) -+#define DMISGR1_MF2_SPK_INT (1 << 5) -+#define DMISGR1_MF2_OUT_INT (1 << 4) -+#define DMISGR1_MF1_SPK_INT (1 << 3) -+#define DMISGR1_MF1_OUT_INT (1 << 2) -+#define DMISGR1_MF0_SPK_INT (1 << 1) -+#define DMISGR1_MF0_OUT_INT (1 << 0) -+#define DMISGR1_MF_OUTSPK_INT(fifo) (0x3 << (fifo) * 2) -+ -+/* Device Mask of Interrupt Source Group 2 Register (0x13C) */ -+#define FOTG210_DMISGR2 0x13C -+#define DMISGR2_MDMA_ERROR (1 << 8) -+#define DMISGR2_MDMA_CMPLT (1 << 7) -+ -+/* Device Interrupt group Register (0x140) */ -+#define FOTG210_DIGR 0x140 -+#define DIGR_INT_G2 (1 << 2) -+#define DIGR_INT_G1 (1 << 1) -+#define DIGR_INT_G0 (1 << 0) -+ -+/* Device Interrupt Source Group 0 Register (0x144) */ -+#define FOTG210_DISGR0 0x144 -+#define DISGR0_CX_COMABT_INT (1 << 5) -+#define DISGR0_CX_COMFAIL_INT (1 << 4) -+#define DISGR0_CX_COMEND_INT (1 << 3) -+#define DISGR0_CX_OUT_INT (1 << 2) -+#define DISGR0_CX_IN_INT (1 << 1) -+#define DISGR0_CX_SETUP_INT (1 << 0) -+ -+/* Device Interrupt Source Group 1 Register (0x148) */ -+#define FOTG210_DISGR1 0x148 -+#define DISGR1_OUT_INT(fifo) (1 << ((fifo) * 2)) -+#define DISGR1_SPK_INT(fifo) (1 << 1 << ((fifo) * 2)) -+#define DISGR1_IN_INT(fifo) (1 << 16 << (fifo)) -+ -+/* Device Interrupt Source Group 2 Register (0x14C) */ -+#define FOTG210_DISGR2 0x14C -+#define DISGR2_DMA_ERROR (1 << 8) -+#define DISGR2_DMA_CMPLT (1 << 7) -+#define DISGR2_RX0BYTE_INT (1 << 6) -+#define DISGR2_TX0BYTE_INT (1 << 5) -+#define DISGR2_ISO_SEQ_ABORT_INT (1 << 4) -+#define DISGR2_ISO_SEQ_ERR_INT (1 << 3) -+#define DISGR2_RESM_INT (1 << 2) -+#define DISGR2_SUSP_INT (1 << 1) -+#define DISGR2_USBRST_INT (1 << 0) -+ -+/* Device Receive Zero-Length Data Packet Register (0x150)*/ -+#define FOTG210_RX0BYTE 0x150 -+#define RX0BYTE_EP8 (1 << 7) -+#define RX0BYTE_EP7 (1 << 6) -+#define RX0BYTE_EP6 (1 << 5) -+#define RX0BYTE_EP5 (1 << 4) -+#define RX0BYTE_EP4 (1 << 3) -+#define RX0BYTE_EP3 (1 << 2) -+#define RX0BYTE_EP2 (1 << 1) -+#define RX0BYTE_EP1 (1 << 0) -+ -+/* Device Transfer Zero-Length Data Packet Register (0x154)*/ -+#define FOTG210_TX0BYTE 0x154 -+#define TX0BYTE_EP8 (1 << 7) -+#define TX0BYTE_EP7 (1 << 6) -+#define TX0BYTE_EP6 (1 << 5) -+#define TX0BYTE_EP5 (1 << 4) -+#define TX0BYTE_EP4 (1 << 3) -+#define TX0BYTE_EP3 (1 << 2) -+#define TX0BYTE_EP2 (1 << 1) -+#define TX0BYTE_EP1 (1 << 0) -+ -+/* Device IN Endpoint x MaxPacketSize Register(0x160+4*(x-1)) */ -+#define FOTG210_INEPMPSR(ep) (0x160 + 4 * ((ep) - 1)) -+#define INOUTEPMPSR_MPS(mps) ((mps) & 0x2FF) -+#define INOUTEPMPSR_STL_EP (1 << 11) -+#define INOUTEPMPSR_RESET_TSEQ (1 << 12) -+ -+/* Device OUT Endpoint x MaxPacketSize Register(0x180+4*(x-1)) */ -+#define FOTG210_OUTEPMPSR(ep) (0x180 + 4 * ((ep) - 1)) -+ -+/* Device Endpoint 1~4 Map Register (0x1A0) */ -+#define FOTG210_EPMAP 0x1A0 -+#define EPMAP_FIFONO(ep, dir) \ -+ ((((ep) - 1) << ((ep) - 1) * 8) << ((dir) ? 0 : 4)) -+#define EPMAP_FIFONOMSK(ep, dir) \ -+ ((3 << ((ep) - 1) * 8) << ((dir) ? 0 : 4)) -+ -+/* Device FIFO Map Register (0x1A8) */ -+#define FOTG210_FIFOMAP 0x1A8 -+#define FIFOMAP_DIROUT(fifo) (0x0 << 4 << (fifo) * 8) -+#define FIFOMAP_DIRIN(fifo) (0x1 << 4 << (fifo) * 8) -+#define FIFOMAP_BIDIR(fifo) (0x2 << 4 << (fifo) * 8) -+#define FIFOMAP_NA(fifo) (0x3 << 4 << (fifo) * 8) -+#define FIFOMAP_EPNO(ep) ((ep) << ((ep) - 1) * 8) -+#define FIFOMAP_EPNOMSK(ep) (0xF << ((ep) - 1) * 8) -+ -+/* Device FIFO Confuguration Register (0x1AC) */ -+#define FOTG210_FIFOCF 0x1AC -+#define FIFOCF_TYPE(type, fifo) ((type) << (fifo) * 8) -+#define FIFOCF_BLK_SIN(fifo) (0x0 << (fifo) * 8 << 2) -+#define FIFOCF_BLK_DUB(fifo) (0x1 << (fifo) * 8 << 2) -+#define FIFOCF_BLK_TRI(fifo) (0x2 << (fifo) * 8 << 2) -+#define FIFOCF_BLKSZ_512(fifo) (0x0 << (fifo) * 8 << 4) -+#define FIFOCF_BLKSZ_1024(fifo) (0x1 << (fifo) * 8 << 4) -+#define FIFOCF_FIFO_EN(fifo) (0x1 << (fifo) * 8 << 5) -+ -+/* Device FIFO n Instruction and Byte Count Register (0x1B0+4*n) */ -+#define FOTG210_FIBCR(fifo) (0x1B0 + (fifo) * 4) -+#define FIBCR_BCFX 0x7FF -+#define FIBCR_FFRST (1 << 12) -+ -+/* Device DMA Target FIFO Number Register (0x1C0) */ -+#define FOTG210_DMATFNR 0x1C0 -+#define DMATFNR_ACC_CXF (1 << 4) -+#define DMATFNR_ACC_F3 (1 << 3) -+#define DMATFNR_ACC_F2 (1 << 2) -+#define DMATFNR_ACC_F1 (1 << 1) -+#define DMATFNR_ACC_F0 (1 << 0) -+#define DMATFNR_ACC_FN(fifo) (1 << (fifo)) -+#define DMATFNR_DISDMA 0 -+ -+/* Device DMA Controller Parameter setting 1 Register (0x1C8) */ -+#define FOTG210_DMACPSR1 0x1C8 -+#define DMACPSR1_DMA_LEN(len) (((len) & 0xFFFF) << 8) -+#define DMACPSR1_DMA_ABORT (1 << 3) -+#define DMACPSR1_DMA_TYPE(dir_in) (((dir_in) ? 1 : 0) << 1) -+#define DMACPSR1_DMA_START (1 << 0) -+ -+/* Device DMA Controller Parameter setting 2 Register (0x1CC) */ -+#define FOTG210_DMACPSR2 0x1CC -+ -+/* Device DMA Controller Parameter setting 3 Register (0x1CC) */ -+#define FOTG210_CXPORT 0x1D0 -+ -+struct fotg210_request { -+ struct usb_request req; -+ struct list_head queue; -+}; -+ -+struct fotg210_ep { -+ struct usb_ep ep; -+ struct fotg210_udc *fotg210; -+ -+ struct list_head queue; -+ unsigned stall:1; -+ unsigned wedged:1; -+ unsigned use_dma:1; -+ -+ unsigned char epnum; -+ unsigned char type; -+ unsigned char dir_in; -+ unsigned int maxp; -+ const struct usb_endpoint_descriptor *desc; -+}; -+ -+struct fotg210_udc { -+ spinlock_t lock; /* protect the struct */ -+ void __iomem *reg; -+ -+ unsigned long irq_trigger; -+ -+ struct usb_gadget gadget; -+ struct usb_gadget_driver *driver; -+ -+ struct fotg210_ep *ep[FOTG210_MAX_NUM_EP]; -+ -+ struct usb_request *ep0_req; /* for internal request */ -+ __le16 ep0_data; -+ u8 ep0_dir; /* 0/0x80 out/in */ -+ -+ u8 reenum; /* if re-enumeration */ -+}; -+ -+#define gadget_to_fotg210(g) container_of((g), struct fotg210_udc, gadget) ---- a/drivers/usb/gadget/udc/fotg210.h -+++ /dev/null -@@ -1,249 +0,0 @@ --// SPDX-License-Identifier: GPL-2.0+ --/* -- * Faraday FOTG210 USB OTG controller -- * -- * Copyright (C) 2013 Faraday Technology Corporation -- * Author: Yuan-Hsin Chen -- */ -- --#include -- --#define FOTG210_MAX_NUM_EP 5 /* ep0...ep4 */ --#define FOTG210_MAX_FIFO_NUM 4 /* fifo0...fifo4 */ -- --/* Global Mask of HC/OTG/DEV interrupt Register(0xC4) */ --#define FOTG210_GMIR 0xC4 --#define GMIR_INT_POLARITY 0x8 /*Active High*/ --#define GMIR_MHC_INT 0x4 --#define GMIR_MOTG_INT 0x2 --#define GMIR_MDEV_INT 0x1 -- --/* Device Main Control Register(0x100) */ --#define FOTG210_DMCR 0x100 --#define DMCR_HS_EN (1 << 6) --#define DMCR_CHIP_EN (1 << 5) --#define DMCR_SFRST (1 << 4) --#define DMCR_GOSUSP (1 << 3) --#define DMCR_GLINT_EN (1 << 2) --#define DMCR_HALF_SPEED (1 << 1) --#define DMCR_CAP_RMWAKUP (1 << 0) -- --/* Device Address Register(0x104) */ --#define FOTG210_DAR 0x104 --#define DAR_AFT_CONF (1 << 7) -- --/* Device Test Register(0x108) */ --#define FOTG210_DTR 0x108 --#define DTR_TST_CLRFF (1 << 0) -- --/* PHY Test Mode Selector register(0x114) */ --#define FOTG210_PHYTMSR 0x114 --#define PHYTMSR_TST_PKT (1 << 4) --#define PHYTMSR_TST_SE0NAK (1 << 3) --#define PHYTMSR_TST_KSTA (1 << 2) --#define PHYTMSR_TST_JSTA (1 << 1) --#define PHYTMSR_UNPLUG (1 << 0) -- --/* Cx configuration and FIFO Empty Status register(0x120) */ --#define FOTG210_DCFESR 0x120 --#define DCFESR_FIFO_EMPTY(fifo) (1 << 8 << (fifo)) --#define DCFESR_CX_EMP (1 << 5) --#define DCFESR_CX_CLR (1 << 3) --#define DCFESR_CX_STL (1 << 2) --#define DCFESR_TST_PKDONE (1 << 1) --#define DCFESR_CX_DONE (1 << 0) -- --/* Device IDLE Counter Register(0x124) */ --#define FOTG210_DICR 0x124 -- --/* Device Mask of Interrupt Group Register (0x130) */ --#define FOTG210_DMIGR 0x130 --#define DMIGR_MINT_G0 (1 << 0) -- --/* Device Mask of Interrupt Source Group 0(0x134) */ --#define FOTG210_DMISGR0 0x134 --#define DMISGR0_MCX_COMEND (1 << 3) --#define DMISGR0_MCX_OUT_INT (1 << 2) --#define DMISGR0_MCX_IN_INT (1 << 1) --#define DMISGR0_MCX_SETUP_INT (1 << 0) -- --/* Device Mask of Interrupt Source Group 1 Register(0x138)*/ --#define FOTG210_DMISGR1 0x138 --#define DMISGR1_MF3_IN_INT (1 << 19) --#define DMISGR1_MF2_IN_INT (1 << 18) --#define DMISGR1_MF1_IN_INT (1 << 17) --#define DMISGR1_MF0_IN_INT (1 << 16) --#define DMISGR1_MF_IN_INT(fifo) (1 << (16 + (fifo))) --#define DMISGR1_MF3_SPK_INT (1 << 7) --#define DMISGR1_MF3_OUT_INT (1 << 6) --#define DMISGR1_MF2_SPK_INT (1 << 5) --#define DMISGR1_MF2_OUT_INT (1 << 4) --#define DMISGR1_MF1_SPK_INT (1 << 3) --#define DMISGR1_MF1_OUT_INT (1 << 2) --#define DMISGR1_MF0_SPK_INT (1 << 1) --#define DMISGR1_MF0_OUT_INT (1 << 0) --#define DMISGR1_MF_OUTSPK_INT(fifo) (0x3 << (fifo) * 2) -- --/* Device Mask of Interrupt Source Group 2 Register (0x13C) */ --#define FOTG210_DMISGR2 0x13C --#define DMISGR2_MDMA_ERROR (1 << 8) --#define DMISGR2_MDMA_CMPLT (1 << 7) -- --/* Device Interrupt group Register (0x140) */ --#define FOTG210_DIGR 0x140 --#define DIGR_INT_G2 (1 << 2) --#define DIGR_INT_G1 (1 << 1) --#define DIGR_INT_G0 (1 << 0) -- --/* Device Interrupt Source Group 0 Register (0x144) */ --#define FOTG210_DISGR0 0x144 --#define DISGR0_CX_COMABT_INT (1 << 5) --#define DISGR0_CX_COMFAIL_INT (1 << 4) --#define DISGR0_CX_COMEND_INT (1 << 3) --#define DISGR0_CX_OUT_INT (1 << 2) --#define DISGR0_CX_IN_INT (1 << 1) --#define DISGR0_CX_SETUP_INT (1 << 0) -- --/* Device Interrupt Source Group 1 Register (0x148) */ --#define FOTG210_DISGR1 0x148 --#define DISGR1_OUT_INT(fifo) (1 << ((fifo) * 2)) --#define DISGR1_SPK_INT(fifo) (1 << 1 << ((fifo) * 2)) --#define DISGR1_IN_INT(fifo) (1 << 16 << (fifo)) -- --/* Device Interrupt Source Group 2 Register (0x14C) */ --#define FOTG210_DISGR2 0x14C --#define DISGR2_DMA_ERROR (1 << 8) --#define DISGR2_DMA_CMPLT (1 << 7) --#define DISGR2_RX0BYTE_INT (1 << 6) --#define DISGR2_TX0BYTE_INT (1 << 5) --#define DISGR2_ISO_SEQ_ABORT_INT (1 << 4) --#define DISGR2_ISO_SEQ_ERR_INT (1 << 3) --#define DISGR2_RESM_INT (1 << 2) --#define DISGR2_SUSP_INT (1 << 1) --#define DISGR2_USBRST_INT (1 << 0) -- --/* Device Receive Zero-Length Data Packet Register (0x150)*/ --#define FOTG210_RX0BYTE 0x150 --#define RX0BYTE_EP8 (1 << 7) --#define RX0BYTE_EP7 (1 << 6) --#define RX0BYTE_EP6 (1 << 5) --#define RX0BYTE_EP5 (1 << 4) --#define RX0BYTE_EP4 (1 << 3) --#define RX0BYTE_EP3 (1 << 2) --#define RX0BYTE_EP2 (1 << 1) --#define RX0BYTE_EP1 (1 << 0) -- --/* Device Transfer Zero-Length Data Packet Register (0x154)*/ --#define FOTG210_TX0BYTE 0x154 --#define TX0BYTE_EP8 (1 << 7) --#define TX0BYTE_EP7 (1 << 6) --#define TX0BYTE_EP6 (1 << 5) --#define TX0BYTE_EP5 (1 << 4) --#define TX0BYTE_EP4 (1 << 3) --#define TX0BYTE_EP3 (1 << 2) --#define TX0BYTE_EP2 (1 << 1) --#define TX0BYTE_EP1 (1 << 0) -- --/* Device IN Endpoint x MaxPacketSize Register(0x160+4*(x-1)) */ --#define FOTG210_INEPMPSR(ep) (0x160 + 4 * ((ep) - 1)) --#define INOUTEPMPSR_MPS(mps) ((mps) & 0x2FF) --#define INOUTEPMPSR_STL_EP (1 << 11) --#define INOUTEPMPSR_RESET_TSEQ (1 << 12) -- --/* Device OUT Endpoint x MaxPacketSize Register(0x180+4*(x-1)) */ --#define FOTG210_OUTEPMPSR(ep) (0x180 + 4 * ((ep) - 1)) -- --/* Device Endpoint 1~4 Map Register (0x1A0) */ --#define FOTG210_EPMAP 0x1A0 --#define EPMAP_FIFONO(ep, dir) \ -- ((((ep) - 1) << ((ep) - 1) * 8) << ((dir) ? 0 : 4)) --#define EPMAP_FIFONOMSK(ep, dir) \ -- ((3 << ((ep) - 1) * 8) << ((dir) ? 0 : 4)) -- --/* Device FIFO Map Register (0x1A8) */ --#define FOTG210_FIFOMAP 0x1A8 --#define FIFOMAP_DIROUT(fifo) (0x0 << 4 << (fifo) * 8) --#define FIFOMAP_DIRIN(fifo) (0x1 << 4 << (fifo) * 8) --#define FIFOMAP_BIDIR(fifo) (0x2 << 4 << (fifo) * 8) --#define FIFOMAP_NA(fifo) (0x3 << 4 << (fifo) * 8) --#define FIFOMAP_EPNO(ep) ((ep) << ((ep) - 1) * 8) --#define FIFOMAP_EPNOMSK(ep) (0xF << ((ep) - 1) * 8) -- --/* Device FIFO Confuguration Register (0x1AC) */ --#define FOTG210_FIFOCF 0x1AC --#define FIFOCF_TYPE(type, fifo) ((type) << (fifo) * 8) --#define FIFOCF_BLK_SIN(fifo) (0x0 << (fifo) * 8 << 2) --#define FIFOCF_BLK_DUB(fifo) (0x1 << (fifo) * 8 << 2) --#define FIFOCF_BLK_TRI(fifo) (0x2 << (fifo) * 8 << 2) --#define FIFOCF_BLKSZ_512(fifo) (0x0 << (fifo) * 8 << 4) --#define FIFOCF_BLKSZ_1024(fifo) (0x1 << (fifo) * 8 << 4) --#define FIFOCF_FIFO_EN(fifo) (0x1 << (fifo) * 8 << 5) -- --/* Device FIFO n Instruction and Byte Count Register (0x1B0+4*n) */ --#define FOTG210_FIBCR(fifo) (0x1B0 + (fifo) * 4) --#define FIBCR_BCFX 0x7FF --#define FIBCR_FFRST (1 << 12) -- --/* Device DMA Target FIFO Number Register (0x1C0) */ --#define FOTG210_DMATFNR 0x1C0 --#define DMATFNR_ACC_CXF (1 << 4) --#define DMATFNR_ACC_F3 (1 << 3) --#define DMATFNR_ACC_F2 (1 << 2) --#define DMATFNR_ACC_F1 (1 << 1) --#define DMATFNR_ACC_F0 (1 << 0) --#define DMATFNR_ACC_FN(fifo) (1 << (fifo)) --#define DMATFNR_DISDMA 0 -- --/* Device DMA Controller Parameter setting 1 Register (0x1C8) */ --#define FOTG210_DMACPSR1 0x1C8 --#define DMACPSR1_DMA_LEN(len) (((len) & 0xFFFF) << 8) --#define DMACPSR1_DMA_ABORT (1 << 3) --#define DMACPSR1_DMA_TYPE(dir_in) (((dir_in) ? 1 : 0) << 1) --#define DMACPSR1_DMA_START (1 << 0) -- --/* Device DMA Controller Parameter setting 2 Register (0x1CC) */ --#define FOTG210_DMACPSR2 0x1CC -- --/* Device DMA Controller Parameter setting 3 Register (0x1CC) */ --#define FOTG210_CXPORT 0x1D0 -- --struct fotg210_request { -- struct usb_request req; -- struct list_head queue; --}; -- --struct fotg210_ep { -- struct usb_ep ep; -- struct fotg210_udc *fotg210; -- -- struct list_head queue; -- unsigned stall:1; -- unsigned wedged:1; -- unsigned use_dma:1; -- -- unsigned char epnum; -- unsigned char type; -- unsigned char dir_in; -- unsigned int maxp; -- const struct usb_endpoint_descriptor *desc; --}; -- --struct fotg210_udc { -- spinlock_t lock; /* protect the struct */ -- void __iomem *reg; -- -- unsigned long irq_trigger; -- -- struct usb_gadget gadget; -- struct usb_gadget_driver *driver; -- -- struct fotg210_ep *ep[FOTG210_MAX_NUM_EP]; -- -- struct usb_request *ep0_req; /* for internal request */ -- __le16 ep0_data; -- u8 ep0_dir; /* 0/0x80 out/in */ -- -- u8 reenum; /* if re-enumeration */ --}; -- --#define gadget_to_fotg210(g) container_of((g), struct fotg210_udc, gadget) ---- a/drivers/usb/host/fotg210.h -+++ /dev/null -@@ -1,688 +0,0 @@ --/* SPDX-License-Identifier: GPL-2.0 */ --#ifndef __LINUX_FOTG210_H --#define __LINUX_FOTG210_H -- --#include -- --/* definitions used for the EHCI driver */ -- --/* -- * __hc32 and __hc16 are "Host Controller" types, they may be equivalent to -- * __leXX (normally) or __beXX (given FOTG210_BIG_ENDIAN_DESC), depending on -- * the host controller implementation. -- * -- * To facilitate the strongest possible byte-order checking from "sparse" -- * and so on, we use __leXX unless that's not practical. -- */ --#define __hc32 __le32 --#define __hc16 __le16 -- --/* statistics can be kept for tuning/monitoring */ --struct fotg210_stats { -- /* irq usage */ -- unsigned long normal; -- unsigned long error; -- unsigned long iaa; -- unsigned long lost_iaa; -- -- /* termination of urbs from core */ -- unsigned long complete; -- unsigned long unlink; --}; -- --/* fotg210_hcd->lock guards shared data against other CPUs: -- * fotg210_hcd: async, unlink, periodic (and shadow), ... -- * usb_host_endpoint: hcpriv -- * fotg210_qh: qh_next, qtd_list -- * fotg210_qtd: qtd_list -- * -- * Also, hold this lock when talking to HC registers or -- * when updating hw_* fields in shared qh/qtd/... structures. -- */ -- --#define FOTG210_MAX_ROOT_PORTS 1 /* see HCS_N_PORTS */ -- --/* -- * fotg210_rh_state values of FOTG210_RH_RUNNING or above mean that the -- * controller may be doing DMA. Lower values mean there's no DMA. -- */ --enum fotg210_rh_state { -- FOTG210_RH_HALTED, -- FOTG210_RH_SUSPENDED, -- FOTG210_RH_RUNNING, -- FOTG210_RH_STOPPING --}; -- --/* -- * Timer events, ordered by increasing delay length. -- * Always update event_delays_ns[] and event_handlers[] (defined in -- * ehci-timer.c) in parallel with this list. -- */ --enum fotg210_hrtimer_event { -- FOTG210_HRTIMER_POLL_ASS, /* Poll for async schedule off */ -- FOTG210_HRTIMER_POLL_PSS, /* Poll for periodic schedule off */ -- FOTG210_HRTIMER_POLL_DEAD, /* Wait for dead controller to stop */ -- FOTG210_HRTIMER_UNLINK_INTR, /* Wait for interrupt QH unlink */ -- FOTG210_HRTIMER_FREE_ITDS, /* Wait for unused iTDs and siTDs */ -- FOTG210_HRTIMER_ASYNC_UNLINKS, /* Unlink empty async QHs */ -- FOTG210_HRTIMER_IAA_WATCHDOG, /* Handle lost IAA interrupts */ -- FOTG210_HRTIMER_DISABLE_PERIODIC, /* Wait to disable periodic sched */ -- FOTG210_HRTIMER_DISABLE_ASYNC, /* Wait to disable async sched */ -- FOTG210_HRTIMER_IO_WATCHDOG, /* Check for missing IRQs */ -- FOTG210_HRTIMER_NUM_EVENTS /* Must come last */ --}; --#define FOTG210_HRTIMER_NO_EVENT 99 -- --struct fotg210_hcd { /* one per controller */ -- /* timing support */ -- enum fotg210_hrtimer_event next_hrtimer_event; -- unsigned enabled_hrtimer_events; -- ktime_t hr_timeouts[FOTG210_HRTIMER_NUM_EVENTS]; -- struct hrtimer hrtimer; -- -- int PSS_poll_count; -- int ASS_poll_count; -- int died_poll_count; -- -- /* glue to PCI and HCD framework */ -- struct fotg210_caps __iomem *caps; -- struct fotg210_regs __iomem *regs; -- struct ehci_dbg_port __iomem *debug; -- -- __u32 hcs_params; /* cached register copy */ -- spinlock_t lock; -- enum fotg210_rh_state rh_state; -- -- /* general schedule support */ -- bool scanning:1; -- bool need_rescan:1; -- bool intr_unlinking:1; -- bool async_unlinking:1; -- bool shutdown:1; -- struct fotg210_qh *qh_scan_next; -- -- /* async schedule support */ -- struct fotg210_qh *async; -- struct fotg210_qh *dummy; /* For AMD quirk use */ -- struct fotg210_qh *async_unlink; -- struct fotg210_qh *async_unlink_last; -- struct fotg210_qh *async_iaa; -- unsigned async_unlink_cycle; -- unsigned async_count; /* async activity count */ -- -- /* periodic schedule support */ --#define DEFAULT_I_TDPS 1024 /* some HCs can do less */ -- unsigned periodic_size; -- __hc32 *periodic; /* hw periodic table */ -- dma_addr_t periodic_dma; -- struct list_head intr_qh_list; -- unsigned i_thresh; /* uframes HC might cache */ -- -- union fotg210_shadow *pshadow; /* mirror hw periodic table */ -- struct fotg210_qh *intr_unlink; -- struct fotg210_qh *intr_unlink_last; -- unsigned intr_unlink_cycle; -- unsigned now_frame; /* frame from HC hardware */ -- unsigned next_frame; /* scan periodic, start here */ -- unsigned intr_count; /* intr activity count */ -- unsigned isoc_count; /* isoc activity count */ -- unsigned periodic_count; /* periodic activity count */ -- /* max periodic time per uframe */ -- unsigned uframe_periodic_max; -- -- -- /* list of itds completed while now_frame was still active */ -- struct list_head cached_itd_list; -- struct fotg210_itd *last_itd_to_free; -- -- /* per root hub port */ -- unsigned long reset_done[FOTG210_MAX_ROOT_PORTS]; -- -- /* bit vectors (one bit per port) -- * which ports were already suspended at the start of a bus suspend -- */ -- unsigned long bus_suspended; -- -- /* which ports are edicated to the companion controller */ -- unsigned long companion_ports; -- -- /* which ports are owned by the companion during a bus suspend */ -- unsigned long owned_ports; -- -- /* which ports have the change-suspend feature turned on */ -- unsigned long port_c_suspend; -- -- /* which ports are suspended */ -- unsigned long suspended_ports; -- -- /* which ports have started to resume */ -- unsigned long resuming_ports; -- -- /* per-HC memory pools (could be per-bus, but ...) */ -- struct dma_pool *qh_pool; /* qh per active urb */ -- struct dma_pool *qtd_pool; /* one or more per qh */ -- struct dma_pool *itd_pool; /* itd per iso urb */ -- -- unsigned random_frame; -- unsigned long next_statechange; -- ktime_t last_periodic_enable; -- u32 command; -- -- /* SILICON QUIRKS */ -- unsigned need_io_watchdog:1; -- unsigned fs_i_thresh:1; /* Intel iso scheduling */ -- -- u8 sbrn; /* packed release number */ -- -- /* irq statistics */ --#ifdef FOTG210_STATS -- struct fotg210_stats stats; --# define INCR(x) ((x)++) --#else --# define INCR(x) do {} while (0) --#endif -- -- /* silicon clock */ -- struct clk *pclk; --}; -- --/* convert between an HCD pointer and the corresponding FOTG210_HCD */ --static inline struct fotg210_hcd *hcd_to_fotg210(struct usb_hcd *hcd) --{ -- return (struct fotg210_hcd *)(hcd->hcd_priv); --} --static inline struct usb_hcd *fotg210_to_hcd(struct fotg210_hcd *fotg210) --{ -- return container_of((void *) fotg210, struct usb_hcd, hcd_priv); --} -- --/*-------------------------------------------------------------------------*/ -- --/* EHCI register interface, corresponds to EHCI Revision 0.95 specification */ -- --/* Section 2.2 Host Controller Capability Registers */ --struct fotg210_caps { -- /* these fields are specified as 8 and 16 bit registers, -- * but some hosts can't perform 8 or 16 bit PCI accesses. -- * some hosts treat caplength and hciversion as parts of a 32-bit -- * register, others treat them as two separate registers, this -- * affects the memory map for big endian controllers. -- */ -- u32 hc_capbase; --#define HC_LENGTH(fotg210, p) (0x00ff&((p) >> /* bits 7:0 / offset 00h */ \ -- (fotg210_big_endian_capbase(fotg210) ? 24 : 0))) --#define HC_VERSION(fotg210, p) (0xffff&((p) >> /* bits 31:16 / offset 02h */ \ -- (fotg210_big_endian_capbase(fotg210) ? 0 : 16))) -- u32 hcs_params; /* HCSPARAMS - offset 0x4 */ --#define HCS_N_PORTS(p) (((p)>>0)&0xf) /* bits 3:0, ports on HC */ -- -- u32 hcc_params; /* HCCPARAMS - offset 0x8 */ --#define HCC_CANPARK(p) ((p)&(1 << 2)) /* true: can park on async qh */ --#define HCC_PGM_FRAMELISTLEN(p) ((p)&(1 << 1)) /* true: periodic_size changes*/ -- u8 portroute[8]; /* nibbles for routing - offset 0xC */ --}; -- -- --/* Section 2.3 Host Controller Operational Registers */ --struct fotg210_regs { -- -- /* USBCMD: offset 0x00 */ -- u32 command; -- --/* EHCI 1.1 addendum */ --/* 23:16 is r/w intr rate, in microframes; default "8" == 1/msec */ --#define CMD_PARK (1<<11) /* enable "park" on async qh */ --#define CMD_PARK_CNT(c) (((c)>>8)&3) /* how many transfers to park for */ --#define CMD_IAAD (1<<6) /* "doorbell" interrupt async advance */ --#define CMD_ASE (1<<5) /* async schedule enable */ --#define CMD_PSE (1<<4) /* periodic schedule enable */ --/* 3:2 is periodic frame list size */ --#define CMD_RESET (1<<1) /* reset HC not bus */ --#define CMD_RUN (1<<0) /* start/stop HC */ -- -- /* USBSTS: offset 0x04 */ -- u32 status; --#define STS_ASS (1<<15) /* Async Schedule Status */ --#define STS_PSS (1<<14) /* Periodic Schedule Status */ --#define STS_RECL (1<<13) /* Reclamation */ --#define STS_HALT (1<<12) /* Not running (any reason) */ --/* some bits reserved */ -- /* these STS_* flags are also intr_enable bits (USBINTR) */ --#define STS_IAA (1<<5) /* Interrupted on async advance */ --#define STS_FATAL (1<<4) /* such as some PCI access errors */ --#define STS_FLR (1<<3) /* frame list rolled over */ --#define STS_PCD (1<<2) /* port change detect */ --#define STS_ERR (1<<1) /* "error" completion (overflow, ...) */ --#define STS_INT (1<<0) /* "normal" completion (short, ...) */ -- -- /* USBINTR: offset 0x08 */ -- u32 intr_enable; -- -- /* FRINDEX: offset 0x0C */ -- u32 frame_index; /* current microframe number */ -- /* CTRLDSSEGMENT: offset 0x10 */ -- u32 segment; /* address bits 63:32 if needed */ -- /* PERIODICLISTBASE: offset 0x14 */ -- u32 frame_list; /* points to periodic list */ -- /* ASYNCLISTADDR: offset 0x18 */ -- u32 async_next; /* address of next async queue head */ -- -- u32 reserved1; -- /* PORTSC: offset 0x20 */ -- u32 port_status; --/* 31:23 reserved */ --#define PORT_USB11(x) (((x)&(3<<10)) == (1<<10)) /* USB 1.1 device */ --#define PORT_RESET (1<<8) /* reset port */ --#define PORT_SUSPEND (1<<7) /* suspend port */ --#define PORT_RESUME (1<<6) /* resume it */ --#define PORT_PEC (1<<3) /* port enable change */ --#define PORT_PE (1<<2) /* port enable */ --#define PORT_CSC (1<<1) /* connect status change */ --#define PORT_CONNECT (1<<0) /* device connected */ --#define PORT_RWC_BITS (PORT_CSC | PORT_PEC) -- u32 reserved2[19]; -- -- /* OTGCSR: offet 0x70 */ -- u32 otgcsr; --#define OTGCSR_HOST_SPD_TYP (3 << 22) --#define OTGCSR_A_BUS_DROP (1 << 5) --#define OTGCSR_A_BUS_REQ (1 << 4) -- -- /* OTGISR: offset 0x74 */ -- u32 otgisr; --#define OTGISR_OVC (1 << 10) -- -- u32 reserved3[15]; -- -- /* GMIR: offset 0xB4 */ -- u32 gmir; --#define GMIR_INT_POLARITY (1 << 3) /*Active High*/ --#define GMIR_MHC_INT (1 << 2) --#define GMIR_MOTG_INT (1 << 1) --#define GMIR_MDEV_INT (1 << 0) --}; -- --/*-------------------------------------------------------------------------*/ -- --#define QTD_NEXT(fotg210, dma) cpu_to_hc32(fotg210, (u32)dma) -- --/* -- * EHCI Specification 0.95 Section 3.5 -- * QTD: describe data transfer components (buffer, direction, ...) -- * See Fig 3-6 "Queue Element Transfer Descriptor Block Diagram". -- * -- * These are associated only with "QH" (Queue Head) structures, -- * used with control, bulk, and interrupt transfers. -- */ --struct fotg210_qtd { -- /* first part defined by EHCI spec */ -- __hc32 hw_next; /* see EHCI 3.5.1 */ -- __hc32 hw_alt_next; /* see EHCI 3.5.2 */ -- __hc32 hw_token; /* see EHCI 3.5.3 */ --#define QTD_TOGGLE (1 << 31) /* data toggle */ --#define QTD_LENGTH(tok) (((tok)>>16) & 0x7fff) --#define QTD_IOC (1 << 15) /* interrupt on complete */ --#define QTD_CERR(tok) (((tok)>>10) & 0x3) --#define QTD_PID(tok) (((tok)>>8) & 0x3) --#define QTD_STS_ACTIVE (1 << 7) /* HC may execute this */ --#define QTD_STS_HALT (1 << 6) /* halted on error */ --#define QTD_STS_DBE (1 << 5) /* data buffer error (in HC) */ --#define QTD_STS_BABBLE (1 << 4) /* device was babbling (qtd halted) */ --#define QTD_STS_XACT (1 << 3) /* device gave illegal response */ --#define QTD_STS_MMF (1 << 2) /* incomplete split transaction */ --#define QTD_STS_STS (1 << 1) /* split transaction state */ --#define QTD_STS_PING (1 << 0) /* issue PING? */ -- --#define ACTIVE_BIT(fotg210) cpu_to_hc32(fotg210, QTD_STS_ACTIVE) --#define HALT_BIT(fotg210) cpu_to_hc32(fotg210, QTD_STS_HALT) --#define STATUS_BIT(fotg210) cpu_to_hc32(fotg210, QTD_STS_STS) -- -- __hc32 hw_buf[5]; /* see EHCI 3.5.4 */ -- __hc32 hw_buf_hi[5]; /* Appendix B */ -- -- /* the rest is HCD-private */ -- dma_addr_t qtd_dma; /* qtd address */ -- struct list_head qtd_list; /* sw qtd list */ -- struct urb *urb; /* qtd's urb */ -- size_t length; /* length of buffer */ --} __aligned(32); -- --/* mask NakCnt+T in qh->hw_alt_next */ --#define QTD_MASK(fotg210) cpu_to_hc32(fotg210, ~0x1f) -- --#define IS_SHORT_READ(token) (QTD_LENGTH(token) != 0 && QTD_PID(token) == 1) -- --/*-------------------------------------------------------------------------*/ -- --/* type tag from {qh,itd,fstn}->hw_next */ --#define Q_NEXT_TYPE(fotg210, dma) ((dma) & cpu_to_hc32(fotg210, 3 << 1)) -- --/* -- * Now the following defines are not converted using the -- * cpu_to_le32() macro anymore, since we have to support -- * "dynamic" switching between be and le support, so that the driver -- * can be used on one system with SoC EHCI controller using big-endian -- * descriptors as well as a normal little-endian PCI EHCI controller. -- */ --/* values for that type tag */ --#define Q_TYPE_ITD (0 << 1) --#define Q_TYPE_QH (1 << 1) --#define Q_TYPE_SITD (2 << 1) --#define Q_TYPE_FSTN (3 << 1) -- --/* next async queue entry, or pointer to interrupt/periodic QH */ --#define QH_NEXT(fotg210, dma) \ -- (cpu_to_hc32(fotg210, (((u32)dma)&~0x01f)|Q_TYPE_QH)) -- --/* for periodic/async schedules and qtd lists, mark end of list */ --#define FOTG210_LIST_END(fotg210) \ -- cpu_to_hc32(fotg210, 1) /* "null pointer" to hw */ -- --/* -- * Entries in periodic shadow table are pointers to one of four kinds -- * of data structure. That's dictated by the hardware; a type tag is -- * encoded in the low bits of the hardware's periodic schedule. Use -- * Q_NEXT_TYPE to get the tag. -- * -- * For entries in the async schedule, the type tag always says "qh". -- */ --union fotg210_shadow { -- struct fotg210_qh *qh; /* Q_TYPE_QH */ -- struct fotg210_itd *itd; /* Q_TYPE_ITD */ -- struct fotg210_fstn *fstn; /* Q_TYPE_FSTN */ -- __hc32 *hw_next; /* (all types) */ -- void *ptr; --}; -- --/*-------------------------------------------------------------------------*/ -- --/* -- * EHCI Specification 0.95 Section 3.6 -- * QH: describes control/bulk/interrupt endpoints -- * See Fig 3-7 "Queue Head Structure Layout". -- * -- * These appear in both the async and (for interrupt) periodic schedules. -- */ -- --/* first part defined by EHCI spec */ --struct fotg210_qh_hw { -- __hc32 hw_next; /* see EHCI 3.6.1 */ -- __hc32 hw_info1; /* see EHCI 3.6.2 */ --#define QH_CONTROL_EP (1 << 27) /* FS/LS control endpoint */ --#define QH_HEAD (1 << 15) /* Head of async reclamation list */ --#define QH_TOGGLE_CTL (1 << 14) /* Data toggle control */ --#define QH_HIGH_SPEED (2 << 12) /* Endpoint speed */ --#define QH_LOW_SPEED (1 << 12) --#define QH_FULL_SPEED (0 << 12) --#define QH_INACTIVATE (1 << 7) /* Inactivate on next transaction */ -- __hc32 hw_info2; /* see EHCI 3.6.2 */ --#define QH_SMASK 0x000000ff --#define QH_CMASK 0x0000ff00 --#define QH_HUBADDR 0x007f0000 --#define QH_HUBPORT 0x3f800000 --#define QH_MULT 0xc0000000 -- __hc32 hw_current; /* qtd list - see EHCI 3.6.4 */ -- -- /* qtd overlay (hardware parts of a struct fotg210_qtd) */ -- __hc32 hw_qtd_next; -- __hc32 hw_alt_next; -- __hc32 hw_token; -- __hc32 hw_buf[5]; -- __hc32 hw_buf_hi[5]; --} __aligned(32); -- --struct fotg210_qh { -- struct fotg210_qh_hw *hw; /* Must come first */ -- /* the rest is HCD-private */ -- dma_addr_t qh_dma; /* address of qh */ -- union fotg210_shadow qh_next; /* ptr to qh; or periodic */ -- struct list_head qtd_list; /* sw qtd list */ -- struct list_head intr_node; /* list of intr QHs */ -- struct fotg210_qtd *dummy; -- struct fotg210_qh *unlink_next; /* next on unlink list */ -- -- unsigned unlink_cycle; -- -- u8 needs_rescan; /* Dequeue during giveback */ -- u8 qh_state; --#define QH_STATE_LINKED 1 /* HC sees this */ --#define QH_STATE_UNLINK 2 /* HC may still see this */ --#define QH_STATE_IDLE 3 /* HC doesn't see this */ --#define QH_STATE_UNLINK_WAIT 4 /* LINKED and on unlink q */ --#define QH_STATE_COMPLETING 5 /* don't touch token.HALT */ -- -- u8 xacterrs; /* XactErr retry counter */ --#define QH_XACTERR_MAX 32 /* XactErr retry limit */ -- -- /* periodic schedule info */ -- u8 usecs; /* intr bandwidth */ -- u8 gap_uf; /* uframes split/csplit gap */ -- u8 c_usecs; /* ... split completion bw */ -- u16 tt_usecs; /* tt downstream bandwidth */ -- unsigned short period; /* polling interval */ -- unsigned short start; /* where polling starts */ --#define NO_FRAME ((unsigned short)~0) /* pick new start */ -- -- struct usb_device *dev; /* access to TT */ -- unsigned is_out:1; /* bulk or intr OUT */ -- unsigned clearing_tt:1; /* Clear-TT-Buf in progress */ --}; -- --/*-------------------------------------------------------------------------*/ -- --/* description of one iso transaction (up to 3 KB data if highspeed) */ --struct fotg210_iso_packet { -- /* These will be copied to iTD when scheduling */ -- u64 bufp; /* itd->hw_bufp{,_hi}[pg] |= */ -- __hc32 transaction; /* itd->hw_transaction[i] |= */ -- u8 cross; /* buf crosses pages */ -- /* for full speed OUT splits */ -- u32 buf1; --}; -- --/* temporary schedule data for packets from iso urbs (both speeds) -- * each packet is one logical usb transaction to the device (not TT), -- * beginning at stream->next_uframe -- */ --struct fotg210_iso_sched { -- struct list_head td_list; -- unsigned span; -- struct fotg210_iso_packet packet[]; --}; -- --/* -- * fotg210_iso_stream - groups all (s)itds for this endpoint. -- * acts like a qh would, if EHCI had them for ISO. -- */ --struct fotg210_iso_stream { -- /* first field matches fotg210_hq, but is NULL */ -- struct fotg210_qh_hw *hw; -- -- u8 bEndpointAddress; -- u8 highspeed; -- struct list_head td_list; /* queued itds */ -- struct list_head free_list; /* list of unused itds */ -- struct usb_device *udev; -- struct usb_host_endpoint *ep; -- -- /* output of (re)scheduling */ -- int next_uframe; -- __hc32 splits; -- -- /* the rest is derived from the endpoint descriptor, -- * trusting urb->interval == f(epdesc->bInterval) and -- * including the extra info for hw_bufp[0..2] -- */ -- u8 usecs, c_usecs; -- u16 interval; -- u16 tt_usecs; -- u16 maxp; -- u16 raw_mask; -- unsigned bandwidth; -- -- /* This is used to initialize iTD's hw_bufp fields */ -- __hc32 buf0; -- __hc32 buf1; -- __hc32 buf2; -- -- /* this is used to initialize sITD's tt info */ -- __hc32 address; --}; -- --/*-------------------------------------------------------------------------*/ -- --/* -- * EHCI Specification 0.95 Section 3.3 -- * Fig 3-4 "Isochronous Transaction Descriptor (iTD)" -- * -- * Schedule records for high speed iso xfers -- */ --struct fotg210_itd { -- /* first part defined by EHCI spec */ -- __hc32 hw_next; /* see EHCI 3.3.1 */ -- __hc32 hw_transaction[8]; /* see EHCI 3.3.2 */ --#define FOTG210_ISOC_ACTIVE (1<<31) /* activate transfer this slot */ --#define FOTG210_ISOC_BUF_ERR (1<<30) /* Data buffer error */ --#define FOTG210_ISOC_BABBLE (1<<29) /* babble detected */ --#define FOTG210_ISOC_XACTERR (1<<28) /* XactErr - transaction error */ --#define FOTG210_ITD_LENGTH(tok) (((tok)>>16) & 0x0fff) --#define FOTG210_ITD_IOC (1 << 15) /* interrupt on complete */ -- --#define ITD_ACTIVE(fotg210) cpu_to_hc32(fotg210, FOTG210_ISOC_ACTIVE) -- -- __hc32 hw_bufp[7]; /* see EHCI 3.3.3 */ -- __hc32 hw_bufp_hi[7]; /* Appendix B */ -- -- /* the rest is HCD-private */ -- dma_addr_t itd_dma; /* for this itd */ -- union fotg210_shadow itd_next; /* ptr to periodic q entry */ -- -- struct urb *urb; -- struct fotg210_iso_stream *stream; /* endpoint's queue */ -- struct list_head itd_list; /* list of stream's itds */ -- -- /* any/all hw_transactions here may be used by that urb */ -- unsigned frame; /* where scheduled */ -- unsigned pg; -- unsigned index[8]; /* in urb->iso_frame_desc */ --} __aligned(32); -- --/*-------------------------------------------------------------------------*/ -- --/* -- * EHCI Specification 0.96 Section 3.7 -- * Periodic Frame Span Traversal Node (FSTN) -- * -- * Manages split interrupt transactions (using TT) that span frame boundaries -- * into uframes 0/1; see 4.12.2.2. In those uframes, a "save place" FSTN -- * makes the HC jump (back) to a QH to scan for fs/ls QH completions until -- * it hits a "restore" FSTN; then it returns to finish other uframe 0/1 work. -- */ --struct fotg210_fstn { -- __hc32 hw_next; /* any periodic q entry */ -- __hc32 hw_prev; /* qh or FOTG210_LIST_END */ -- -- /* the rest is HCD-private */ -- dma_addr_t fstn_dma; -- union fotg210_shadow fstn_next; /* ptr to periodic q entry */ --} __aligned(32); -- --/*-------------------------------------------------------------------------*/ -- --/* Prepare the PORTSC wakeup flags during controller suspend/resume */ -- --#define fotg210_prepare_ports_for_controller_suspend(fotg210, do_wakeup) \ -- fotg210_adjust_port_wakeup_flags(fotg210, true, do_wakeup) -- --#define fotg210_prepare_ports_for_controller_resume(fotg210) \ -- fotg210_adjust_port_wakeup_flags(fotg210, false, false) -- --/*-------------------------------------------------------------------------*/ -- --/* -- * Some EHCI controllers have a Transaction Translator built into the -- * root hub. This is a non-standard feature. Each controller will need -- * to add code to the following inline functions, and call them as -- * needed (mostly in root hub code). -- */ -- --static inline unsigned int --fotg210_get_speed(struct fotg210_hcd *fotg210, unsigned int portsc) --{ -- return (readl(&fotg210->regs->otgcsr) -- & OTGCSR_HOST_SPD_TYP) >> 22; --} -- --/* Returns the speed of a device attached to a port on the root hub. */ --static inline unsigned int --fotg210_port_speed(struct fotg210_hcd *fotg210, unsigned int portsc) --{ -- switch (fotg210_get_speed(fotg210, portsc)) { -- case 0: -- return 0; -- case 1: -- return USB_PORT_STAT_LOW_SPEED; -- case 2: -- default: -- return USB_PORT_STAT_HIGH_SPEED; -- } --} -- --/*-------------------------------------------------------------------------*/ -- --#define fotg210_has_fsl_portno_bug(e) (0) -- --/* -- * While most USB host controllers implement their registers in -- * little-endian format, a minority (celleb companion chip) implement -- * them in big endian format. -- * -- * This attempts to support either format at compile time without a -- * runtime penalty, or both formats with the additional overhead -- * of checking a flag bit. -- * -- */ -- --#define fotg210_big_endian_mmio(e) 0 --#define fotg210_big_endian_capbase(e) 0 -- --static inline unsigned int fotg210_readl(const struct fotg210_hcd *fotg210, -- __u32 __iomem *regs) --{ -- return readl(regs); --} -- --static inline void fotg210_writel(const struct fotg210_hcd *fotg210, -- const unsigned int val, __u32 __iomem *regs) --{ -- writel(val, regs); --} -- --/* cpu to fotg210 */ --static inline __hc32 cpu_to_hc32(const struct fotg210_hcd *fotg210, const u32 x) --{ -- return cpu_to_le32(x); --} -- --/* fotg210 to cpu */ --static inline u32 hc32_to_cpu(const struct fotg210_hcd *fotg210, const __hc32 x) --{ -- return le32_to_cpu(x); --} -- --static inline u32 hc32_to_cpup(const struct fotg210_hcd *fotg210, -- const __hc32 *x) --{ -- return le32_to_cpup(x); --} -- --/*-------------------------------------------------------------------------*/ -- --static inline unsigned fotg210_read_frame_index(struct fotg210_hcd *fotg210) --{ -- return fotg210_readl(fotg210, &fotg210->regs->frame_index); --} -- --/*-------------------------------------------------------------------------*/ -- --#endif /* __LINUX_FOTG210_H */ diff --git a/target/linux/gemini/patches-6.1/0003-usb-fotg210-Compile-into-one-module.patch b/target/linux/gemini/patches-6.1/0003-usb-fotg210-Compile-into-one-module.patch deleted file mode 100644 index 5c7b4ff9c79..00000000000 --- a/target/linux/gemini/patches-6.1/0003-usb-fotg210-Compile-into-one-module.patch +++ /dev/null @@ -1,332 +0,0 @@ -From 0dbc77a99267a5efef0603a4b49ac02ece6a3f23 Mon Sep 17 00:00:00 2001 -From: Linus Walleij -Date: Sun, 23 Oct 2022 16:47:07 +0200 -Subject: [PATCH 03/29] usb: fotg210: Compile into one module - -It is since ages perfectly possible to compile both of these -modules into the same kernel, which makes no sense since it -is one piece of hardware. - -Compile one module named "fotg210.ko" for both HCD and UDC -drivers by collecting the init calls into a fotg210-core.c -file and start to centralize things handling one and the same -piece of hardware. - -Stub out the initcalls if one or the other part of the driver -was not selected. - -Tested by compiling one or the other or both of the drivers -into the kernel and as modules. - -Cc: Fabian Vogt -Cc: Yuan-Hsin Chen -Cc: Felipe Balbi -Signed-off-by: Linus Walleij -Link: https://lore.kernel.org/r/20221023144708.3596563-2-linus.walleij@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- ---- a/drivers/usb/fotg210/Kconfig -+++ b/drivers/usb/fotg210/Kconfig -@@ -12,7 +12,7 @@ config USB_FOTG210 - if USB_FOTG210 - - config USB_FOTG210_HCD -- tristate "Faraday FOTG210 USB Host Controller support" -+ bool "Faraday FOTG210 USB Host Controller support" - depends on USB - help - Faraday FOTG210 is an OTG controller which can be configured as -@@ -24,7 +24,7 @@ config USB_FOTG210_HCD - - config USB_FOTG210_UDC - depends on USB_GADGET -- tristate "Faraday FOTG210 USB Peripheral Controller support" -+ bool "Faraday FOTG210 USB Peripheral Controller support" - help - Faraday USB2.0 OTG controller which can be configured as - high speed or full speed USB device. This driver suppports ---- a/drivers/usb/fotg210/Makefile -+++ b/drivers/usb/fotg210/Makefile -@@ -1,3 +1,10 @@ - # SPDX-License-Identifier: GPL-2.0 --obj-$(CONFIG_USB_FOTG210_HCD) += fotg210-hcd.o --obj-$(CONFIG_USB_FOTG210_UDC) += fotg210-udc.o -+ -+# This setup links the different object files into one single -+# module so we don't have to EXPORT() a lot of internal symbols -+# or create unnecessary submodules. -+fotg210-objs-y += fotg210-core.o -+fotg210-objs-$(CONFIG_USB_FOTG210_HCD) += fotg210-hcd.o -+fotg210-objs-$(CONFIG_USB_FOTG210_UDC) += fotg210-udc.o -+fotg210-objs := $(fotg210-objs-y) -+obj-$(CONFIG_USB_FOTG210) += fotg210.o ---- /dev/null -+++ b/drivers/usb/fotg210/fotg210-core.c -@@ -0,0 +1,79 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Central probing code for the FOTG210 dual role driver -+ * We register one driver for the hardware and then we decide -+ * whether to proceed with probing the host or the peripheral -+ * driver. -+ */ -+#include -+#include -+#include -+#include -+#include -+ -+#include "fotg210.h" -+ -+static int fotg210_probe(struct platform_device *pdev) -+{ -+ int ret; -+ -+ if (IS_ENABLED(CONFIG_USB_FOTG210_HCD)) { -+ ret = fotg210_hcd_probe(pdev); -+ if (ret) -+ return ret; -+ } -+ if (IS_ENABLED(CONFIG_USB_FOTG210_UDC)) -+ ret = fotg210_udc_probe(pdev); -+ -+ return ret; -+} -+ -+static int fotg210_remove(struct platform_device *pdev) -+{ -+ if (IS_ENABLED(CONFIG_USB_FOTG210_HCD)) -+ fotg210_hcd_remove(pdev); -+ if (IS_ENABLED(CONFIG_USB_FOTG210_UDC)) -+ fotg210_udc_remove(pdev); -+ -+ return 0; -+} -+ -+#ifdef CONFIG_OF -+static const struct of_device_id fotg210_of_match[] = { -+ { .compatible = "faraday,fotg210" }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, fotg210_of_match); -+#endif -+ -+static struct platform_driver fotg210_driver = { -+ .driver = { -+ .name = "fotg210", -+ .of_match_table = of_match_ptr(fotg210_of_match), -+ }, -+ .probe = fotg210_probe, -+ .remove = fotg210_remove, -+}; -+ -+static int __init fotg210_init(void) -+{ -+ if (usb_disabled()) -+ return -ENODEV; -+ -+ if (IS_ENABLED(CONFIG_USB_FOTG210_HCD)) -+ fotg210_hcd_init(); -+ return platform_driver_register(&fotg210_driver); -+} -+module_init(fotg210_init); -+ -+static void __exit fotg210_cleanup(void) -+{ -+ platform_driver_unregister(&fotg210_driver); -+ if (IS_ENABLED(CONFIG_USB_FOTG210_HCD)) -+ fotg210_hcd_cleanup(); -+} -+module_exit(fotg210_cleanup); -+ -+MODULE_AUTHOR("Yuan-Hsin Chen, Feng-Hsin Chiang"); -+MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("FOTG210 Dual Role Controller Driver"); ---- a/drivers/usb/fotg210/fotg210-hcd.c -+++ b/drivers/usb/fotg210/fotg210-hcd.c -@@ -39,8 +39,8 @@ - #include - #include - --#define DRIVER_AUTHOR "Yuan-Hsin Chen" --#define DRIVER_DESC "FOTG210 Host Controller (EHCI) Driver" -+#include "fotg210.h" -+ - static const char hcd_name[] = "fotg210_hcd"; - - #undef FOTG210_URB_TRACE -@@ -5490,9 +5490,6 @@ static int fotg210_get_frame(struct usb_ - * functions and in order to facilitate role switching we cannot - * give the fotg210 driver exclusive access to those. - */ --MODULE_DESCRIPTION(DRIVER_DESC); --MODULE_AUTHOR(DRIVER_AUTHOR); --MODULE_LICENSE("GPL"); - - static const struct hc_driver fotg210_fotg210_hc_driver = { - .description = hcd_name, -@@ -5560,7 +5557,7 @@ static void fotg210_init(struct fotg210_ - * then invokes the start() method for the HCD associated with it - * through the hotplug entry's driver_data. - */ --static int fotg210_hcd_probe(struct platform_device *pdev) -+int fotg210_hcd_probe(struct platform_device *pdev) - { - struct device *dev = &pdev->dev; - struct usb_hcd *hcd; -@@ -5652,7 +5649,7 @@ fail_create_hcd: - * @dev: USB Host Controller being removed - * - */ --static int fotg210_hcd_remove(struct platform_device *pdev) -+int fotg210_hcd_remove(struct platform_device *pdev) - { - struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); -@@ -5668,27 +5665,8 @@ static int fotg210_hcd_remove(struct pla - return 0; - } - --#ifdef CONFIG_OF --static const struct of_device_id fotg210_of_match[] = { -- { .compatible = "faraday,fotg210" }, -- {}, --}; --MODULE_DEVICE_TABLE(of, fotg210_of_match); --#endif -- --static struct platform_driver fotg210_hcd_driver = { -- .driver = { -- .name = "fotg210-hcd", -- .of_match_table = of_match_ptr(fotg210_of_match), -- }, -- .probe = fotg210_hcd_probe, -- .remove = fotg210_hcd_remove, --}; -- --static int __init fotg210_hcd_init(void) -+int __init fotg210_hcd_init(void) - { -- int retval = 0; -- - if (usb_disabled()) - return -ENODEV; - -@@ -5704,24 +5682,11 @@ static int __init fotg210_hcd_init(void) - - fotg210_debug_root = debugfs_create_dir("fotg210", usb_debug_root); - -- retval = platform_driver_register(&fotg210_hcd_driver); -- if (retval < 0) -- goto clean; -- return retval; -- --clean: -- debugfs_remove(fotg210_debug_root); -- fotg210_debug_root = NULL; -- -- clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded); -- return retval; -+ return 0; - } --module_init(fotg210_hcd_init); - --static void __exit fotg210_hcd_cleanup(void) -+void __exit fotg210_hcd_cleanup(void) - { -- platform_driver_unregister(&fotg210_hcd_driver); - debugfs_remove(fotg210_debug_root); - clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded); - } --module_exit(fotg210_hcd_cleanup); ---- a/drivers/usb/fotg210/fotg210-udc.c -+++ b/drivers/usb/fotg210/fotg210-udc.c -@@ -16,6 +16,7 @@ - #include - #include - -+#include "fotg210.h" - #include "fotg210-udc.h" - - #define DRIVER_DESC "FOTG210 USB Device Controller Driver" -@@ -1081,7 +1082,7 @@ static const struct usb_gadget_ops fotg2 - .udc_stop = fotg210_udc_stop, - }; - --static int fotg210_udc_remove(struct platform_device *pdev) -+int fotg210_udc_remove(struct platform_device *pdev) - { - struct fotg210_udc *fotg210 = platform_get_drvdata(pdev); - int i; -@@ -1098,7 +1099,7 @@ static int fotg210_udc_remove(struct pla - return 0; - } - --static int fotg210_udc_probe(struct platform_device *pdev) -+int fotg210_udc_probe(struct platform_device *pdev) - { - struct resource *res, *ires; - struct fotg210_udc *fotg210 = NULL; -@@ -1223,17 +1224,3 @@ err_alloc: - err: - return ret; - } -- --static struct platform_driver fotg210_driver = { -- .driver = { -- .name = udc_name, -- }, -- .probe = fotg210_udc_probe, -- .remove = fotg210_udc_remove, --}; -- --module_platform_driver(fotg210_driver); -- --MODULE_AUTHOR("Yuan-Hsin Chen, Feng-Hsin Chiang "); --MODULE_LICENSE("GPL"); --MODULE_DESCRIPTION(DRIVER_DESC); ---- /dev/null -+++ b/drivers/usb/fotg210/fotg210.h -@@ -0,0 +1,42 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+#ifndef __FOTG210_H -+#define __FOTG210_H -+ -+#ifdef CONFIG_USB_FOTG210_HCD -+int fotg210_hcd_probe(struct platform_device *pdev); -+int fotg210_hcd_remove(struct platform_device *pdev); -+int fotg210_hcd_init(void); -+void fotg210_hcd_cleanup(void); -+#else -+static inline int fotg210_hcd_probe(struct platform_device *pdev) -+{ -+ return 0; -+} -+static inline int fotg210_hcd_remove(struct platform_device *pdev) -+{ -+ return 0; -+} -+static inline int fotg210_hcd_init(void) -+{ -+ return 0; -+} -+static inline void fotg210_hcd_cleanup(void) -+{ -+} -+#endif -+ -+#ifdef CONFIG_USB_FOTG210_UDC -+int fotg210_udc_probe(struct platform_device *pdev); -+int fotg210_udc_remove(struct platform_device *pdev); -+#else -+static inline int fotg210_udc_probe(struct platform_device *pdev) -+{ -+ return 0; -+} -+static inline int fotg210_udc_remove(struct platform_device *pdev) -+{ -+ return 0; -+} -+#endif -+ -+#endif /* __FOTG210_H */ diff --git a/target/linux/gemini/patches-6.1/0004-usb-fotg210-Select-subdriver-by-mode.patch b/target/linux/gemini/patches-6.1/0004-usb-fotg210-Select-subdriver-by-mode.patch deleted file mode 100644 index 6a19a0aa4d9..00000000000 --- a/target/linux/gemini/patches-6.1/0004-usb-fotg210-Select-subdriver-by-mode.patch +++ /dev/null @@ -1,68 +0,0 @@ -From 7c0b661926097e935f2711857596fc2277b2304a Mon Sep 17 00:00:00 2001 -From: Linus Walleij -Date: Sun, 23 Oct 2022 16:47:08 +0200 -Subject: [PATCH 04/29] usb: fotg210: Select subdriver by mode - -Check which mode the hardware is in, and selecte the peripheral -driver if the hardware is in explicit peripheral mode, otherwise -select host mode. - -This should solve the immediate problem that both subdrivers -can get probed. - -Cc: Fabian Vogt -Cc: Yuan-Hsin Chen -Cc: Felipe Balbi -Signed-off-by: Linus Walleij -Link: https://lore.kernel.org/r/20221023144708.3596563-3-linus.walleij@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- ---- a/drivers/usb/fotg210/fotg210-core.c -+++ b/drivers/usb/fotg210/fotg210-core.c -@@ -10,30 +10,37 @@ - #include - #include - #include -+#include - - #include "fotg210.h" - - static int fotg210_probe(struct platform_device *pdev) - { -+ struct device *dev = &pdev->dev; -+ enum usb_dr_mode mode; - int ret; - -- if (IS_ENABLED(CONFIG_USB_FOTG210_HCD)) { -- ret = fotg210_hcd_probe(pdev); -- if (ret) -- return ret; -- } -- if (IS_ENABLED(CONFIG_USB_FOTG210_UDC)) -+ mode = usb_get_dr_mode(dev); -+ -+ if (mode == USB_DR_MODE_PERIPHERAL) - ret = fotg210_udc_probe(pdev); -+ else -+ ret = fotg210_hcd_probe(pdev); - - return ret; - } - - static int fotg210_remove(struct platform_device *pdev) - { -- if (IS_ENABLED(CONFIG_USB_FOTG210_HCD)) -- fotg210_hcd_remove(pdev); -- if (IS_ENABLED(CONFIG_USB_FOTG210_UDC)) -+ struct device *dev = &pdev->dev; -+ enum usb_dr_mode mode; -+ -+ mode = usb_get_dr_mode(dev); -+ -+ if (mode == USB_DR_MODE_PERIPHERAL) - fotg210_udc_remove(pdev); -+ else -+ fotg210_hcd_remove(pdev); - - return 0; - } diff --git a/target/linux/gemini/patches-6.1/0005-usb-fotg2-add-Gemini-specific-handling.patch b/target/linux/gemini/patches-6.1/0005-usb-fotg2-add-Gemini-specific-handling.patch deleted file mode 100644 index daf8d856117..00000000000 --- a/target/linux/gemini/patches-6.1/0005-usb-fotg2-add-Gemini-specific-handling.patch +++ /dev/null @@ -1,135 +0,0 @@ -From f7f6c8aca91093e2f886ec97910b1a7d9a69bf9b Mon Sep 17 00:00:00 2001 -From: Linus Walleij -Date: Wed, 9 Nov 2022 21:05:54 +0100 -Subject: [PATCH 05/29] usb: fotg2: add Gemini-specific handling - -The Cortina Systems Gemini has bolted on a PHY inside the -silicon that can be handled by six bits in a MISC register in -the system controller. - -If we are running on Gemini, look up a syscon regmap through -a phandle and enable VBUS and optionally the Mini-B connector. - -If the device is flagged as "wakeup-source" using the standard -DT bindings, we also enable this in the global controller for -respective port. - -Signed-off-by: Linus Walleij -Link: https://lore.kernel.org/r/20221109200554.1957185-1-linus.walleij@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- ---- a/drivers/usb/fotg210/Kconfig -+++ b/drivers/usb/fotg210/Kconfig -@@ -5,6 +5,7 @@ config USB_FOTG210 - depends on USB || USB_GADGET - depends on HAS_DMA && HAS_IOMEM - default ARCH_GEMINI -+ select MFD_SYSCON - help - Faraday FOTG210 is a dual-mode USB controller that can act - in both host controller and peripheral controller mode. ---- a/drivers/usb/fotg210/fotg210-core.c -+++ b/drivers/usb/fotg210/fotg210-core.c -@@ -5,15 +5,86 @@ - * whether to proceed with probing the host or the peripheral - * driver. - */ -+#include - #include -+#include - #include - #include - #include -+#include - #include - #include - - #include "fotg210.h" - -+/* -+ * Gemini-specific initialization function, only executed on the -+ * Gemini SoC using the global misc control register. -+ * -+ * The gemini USB blocks are connected to either Mini-A (host mode) or -+ * Mini-B (peripheral mode) plugs. There is no role switch support on the -+ * Gemini SoC, just either-or. -+ */ -+#define GEMINI_GLOBAL_MISC_CTRL 0x30 -+#define GEMINI_MISC_USB0_WAKEUP BIT(14) -+#define GEMINI_MISC_USB1_WAKEUP BIT(15) -+#define GEMINI_MISC_USB0_VBUS_ON BIT(22) -+#define GEMINI_MISC_USB1_VBUS_ON BIT(23) -+#define GEMINI_MISC_USB0_MINI_B BIT(29) -+#define GEMINI_MISC_USB1_MINI_B BIT(30) -+ -+static int fotg210_gemini_init(struct device *dev, struct resource *res, -+ enum usb_dr_mode mode) -+{ -+ struct device_node *np = dev->of_node; -+ struct regmap *map; -+ bool wakeup; -+ u32 mask, val; -+ int ret; -+ -+ map = syscon_regmap_lookup_by_phandle(np, "syscon"); -+ if (IS_ERR(map)) { -+ dev_err(dev, "no syscon\n"); -+ return PTR_ERR(map); -+ } -+ wakeup = of_property_read_bool(np, "wakeup-source"); -+ -+ /* -+ * Figure out if this is USB0 or USB1 by simply checking the -+ * physical base address. -+ */ -+ mask = 0; -+ if (res->start == 0x69000000) { -+ mask = GEMINI_MISC_USB1_VBUS_ON | GEMINI_MISC_USB1_MINI_B | -+ GEMINI_MISC_USB1_WAKEUP; -+ if (mode == USB_DR_MODE_HOST) -+ val = GEMINI_MISC_USB1_VBUS_ON; -+ else -+ val = GEMINI_MISC_USB1_MINI_B; -+ if (wakeup) -+ val |= GEMINI_MISC_USB1_WAKEUP; -+ } else { -+ mask = GEMINI_MISC_USB0_VBUS_ON | GEMINI_MISC_USB0_MINI_B | -+ GEMINI_MISC_USB0_WAKEUP; -+ if (mode == USB_DR_MODE_HOST) -+ val = GEMINI_MISC_USB0_VBUS_ON; -+ else -+ val = GEMINI_MISC_USB0_MINI_B; -+ if (wakeup) -+ val |= GEMINI_MISC_USB0_WAKEUP; -+ } -+ -+ ret = regmap_update_bits(map, GEMINI_GLOBAL_MISC_CTRL, mask, val); -+ if (ret) { -+ dev_err(dev, "failed to initialize Gemini PHY\n"); -+ return ret; -+ } -+ -+ dev_info(dev, "initialized Gemini PHY in %s mode\n", -+ (mode == USB_DR_MODE_HOST) ? "host" : "gadget"); -+ return 0; -+} -+ - static int fotg210_probe(struct platform_device *pdev) - { - struct device *dev = &pdev->dev; -@@ -22,6 +93,15 @@ static int fotg210_probe(struct platform - - mode = usb_get_dr_mode(dev); - -+ if (of_device_is_compatible(dev->of_node, "cortina,gemini-usb")) { -+ struct resource *res; -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ ret = fotg210_gemini_init(dev, res, mode); -+ if (ret) -+ return ret; -+ } -+ - if (mode == USB_DR_MODE_PERIPHERAL) - ret = fotg210_udc_probe(pdev); - else diff --git a/target/linux/gemini/patches-6.1/0006-usb-fotg210-Fix-Kconfig-for-USB-host-modules.patch b/target/linux/gemini/patches-6.1/0006-usb-fotg210-Fix-Kconfig-for-USB-host-modules.patch deleted file mode 100644 index bd3a42415a4..00000000000 --- a/target/linux/gemini/patches-6.1/0006-usb-fotg210-Fix-Kconfig-for-USB-host-modules.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 6e002d41889bc52213a26ff91338d340505e0336 Mon Sep 17 00:00:00 2001 -From: Linus Walleij -Date: Fri, 11 Nov 2022 15:48:21 +0100 -Subject: [PATCH 06/29] usb: fotg210: Fix Kconfig for USB host modules - -The kernel robot reports a link failure when activating the -FOTG210 host subdriver with =y on a system where the USB host -core is a module (CONFIG_USB=m). - -This is a bit of special case, so mimic the Kconfig incantations -from DWC3: let the subdrivers for host or peripheral depend -on the host or gadget support being =y or the same as the -FOTG210 core itself. - -This should ensure that either: - -- The host (CONFIG_USB) or gadget (CONFIG_GADGET) is compiled - in and then the FOTG210 can be either module or compiled - in. - -- The host or gadget is modular, and then the FOTG210 module - must be a module too, or we cannot resolve the symbols - at link time. - -Reported-by: kernel test robot -Link: https://lore.kernel.org/linux-usb/202211112132.0BUPGKCd-lkp@intel.com/ -Cc: Arnd Bergmann -Signed-off-by: Linus Walleij -Link: https://lore.kernel.org/r/20221111144821.113665-1-linus.walleij@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- ---- a/drivers/usb/fotg210/Kconfig -+++ b/drivers/usb/fotg210/Kconfig -@@ -14,7 +14,7 @@ if USB_FOTG210 - - config USB_FOTG210_HCD - bool "Faraday FOTG210 USB Host Controller support" -- depends on USB -+ depends on USB=y || USB=USB_FOTG210 - help - Faraday FOTG210 is an OTG controller which can be configured as - an USB2.0 host. It is designed to meet USB2.0 EHCI specification -@@ -24,7 +24,7 @@ config USB_FOTG210_HCD - module will be called fotg210-hcd. - - config USB_FOTG210_UDC -- depends on USB_GADGET -+ depends on USB_GADGET=y || USB_GADGET=USB_FOTG210 - bool "Faraday FOTG210 USB Peripheral Controller support" - help - Faraday USB2.0 OTG controller which can be configured as diff --git a/target/linux/gemini/patches-6.1/0007-usb-USB_FOTG210-should-depend-on-ARCH_GEMINI.patch b/target/linux/gemini/patches-6.1/0007-usb-USB_FOTG210-should-depend-on-ARCH_GEMINI.patch deleted file mode 100644 index 6afef0d8200..00000000000 --- a/target/linux/gemini/patches-6.1/0007-usb-USB_FOTG210-should-depend-on-ARCH_GEMINI.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 466b10510add46afd21ca19505b29d35ad853370 Mon Sep 17 00:00:00 2001 -From: Geert Uytterhoeven -Date: Mon, 21 Nov 2022 16:22:19 +0100 -Subject: [PATCH 07/29] usb: USB_FOTG210 should depend on ARCH_GEMINI - -The Faraday Technology FOTG210 USB2 Dual Role Controller is only present -on Cortina Systems Gemini SoCs. Hence add a dependency on ARCH_GEMINI, -to prevent asking the user about its drivers when configuring a kernel -without Cortina Systems Gemini SoC support. - -Fixes: 1dd33a9f1b95ab59 ("usb: fotg210: Collect pieces of dual mode controller") -Signed-off-by: Geert Uytterhoeven -Reviewed-by: Linus Walleij -Link: https://lore.kernel.org/r/a989b3b798ecaf3b45f35160e30e605636d66a77.1669044086.git.geert+renesas@glider.be -Signed-off-by: Greg Kroah-Hartman ---- ---- a/drivers/usb/fotg210/Kconfig -+++ b/drivers/usb/fotg210/Kconfig -@@ -4,6 +4,7 @@ config USB_FOTG210 - tristate "Faraday FOTG210 USB2 Dual Role controller" - depends on USB || USB_GADGET - depends on HAS_DMA && HAS_IOMEM -+ depends on ARCH_GEMINI || COMPILE_TEST - default ARCH_GEMINI - select MFD_SYSCON - help diff --git a/target/linux/gemini/patches-6.1/0008-fotg210-udc-Use-dev-pointer-in-probe-and-dev_message.patch b/target/linux/gemini/patches-6.1/0008-fotg210-udc-Use-dev-pointer-in-probe-and-dev_message.patch deleted file mode 100644 index 2a595e885d1..00000000000 --- a/target/linux/gemini/patches-6.1/0008-fotg210-udc-Use-dev-pointer-in-probe-and-dev_message.patch +++ /dev/null @@ -1,61 +0,0 @@ -From 27cd321a365fecac857e41ad1681062994142e4a Mon Sep 17 00:00:00 2001 -From: Linus Walleij -Date: Mon, 14 Nov 2022 12:51:58 +0100 -Subject: [PATCH 08/29] fotg210-udc: Use dev pointer in probe and dev_messages - -Add a local struct device *dev pointer and use dev_err() -etc to report status. - -Signed-off-by: Linus Walleij -Link: https://lore.kernel.org/r/20221114115201.302887-1-linus.walleij@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- ---- a/drivers/usb/fotg210/fotg210-udc.c -+++ b/drivers/usb/fotg210/fotg210-udc.c -@@ -1104,6 +1104,7 @@ int fotg210_udc_probe(struct platform_de - struct resource *res, *ires; - struct fotg210_udc *fotg210 = NULL; - struct fotg210_ep *_ep[FOTG210_MAX_NUM_EP]; -+ struct device *dev = &pdev->dev; - int ret = 0; - int i; - -@@ -1135,7 +1136,7 @@ int fotg210_udc_probe(struct platform_de - - fotg210->reg = ioremap(res->start, resource_size(res)); - if (fotg210->reg == NULL) { -- pr_err("ioremap error.\n"); -+ dev_err(dev, "ioremap error\n"); - goto err_alloc; - } - -@@ -1146,8 +1147,8 @@ int fotg210_udc_probe(struct platform_de - fotg210->gadget.ops = &fotg210_gadget_ops; - - fotg210->gadget.max_speed = USB_SPEED_HIGH; -- fotg210->gadget.dev.parent = &pdev->dev; -- fotg210->gadget.dev.dma_mask = pdev->dev.dma_mask; -+ fotg210->gadget.dev.parent = dev; -+ fotg210->gadget.dev.dma_mask = dev->dma_mask; - fotg210->gadget.name = udc_name; - - INIT_LIST_HEAD(&fotg210->gadget.ep_list); -@@ -1195,15 +1196,15 @@ int fotg210_udc_probe(struct platform_de - ret = request_irq(ires->start, fotg210_irq, IRQF_SHARED, - udc_name, fotg210); - if (ret < 0) { -- pr_err("request_irq error (%d)\n", ret); -+ dev_err(dev, "request_irq error (%d)\n", ret); - goto err_req; - } - -- ret = usb_add_gadget_udc(&pdev->dev, &fotg210->gadget); -+ ret = usb_add_gadget_udc(dev, &fotg210->gadget); - if (ret) - goto err_add_udc; - -- dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION); -+ dev_info(dev, "version %s\n", DRIVER_VERSION); - - return 0; - diff --git a/target/linux/gemini/patches-6.1/0009-fotg210-udc-Support-optional-external-PHY.patch b/target/linux/gemini/patches-6.1/0009-fotg210-udc-Support-optional-external-PHY.patch deleted file mode 100644 index 498875c5356..00000000000 --- a/target/linux/gemini/patches-6.1/0009-fotg210-udc-Support-optional-external-PHY.patch +++ /dev/null @@ -1,158 +0,0 @@ -From 03e4b585ac947e2d422bedf03179bbfec3aca3cf Mon Sep 17 00:00:00 2001 -From: Linus Walleij -Date: Mon, 14 Nov 2022 12:51:59 +0100 -Subject: [PATCH 09/29] fotg210-udc: Support optional external PHY - -This adds support for an optional external PHY to the FOTG210 -UDC driver. - -Tested with the GPIO VBUS PHY driver on the Gemini SoC. - -Signed-off-by: Linus Walleij -Link: https://lore.kernel.org/r/20221114115201.302887-2-linus.walleij@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- ---- a/drivers/usb/fotg210/fotg210-udc.c -+++ b/drivers/usb/fotg210/fotg210-udc.c -@@ -15,6 +15,8 @@ - #include - #include - #include -+#include -+#include - - #include "fotg210.h" - #include "fotg210-udc.h" -@@ -1022,10 +1024,18 @@ static int fotg210_udc_start(struct usb_ - { - struct fotg210_udc *fotg210 = gadget_to_fotg210(g); - u32 value; -+ int ret; - - /* hook up the driver */ - fotg210->driver = driver; - -+ if (!IS_ERR_OR_NULL(fotg210->phy)) { -+ ret = otg_set_peripheral(fotg210->phy->otg, -+ &fotg210->gadget); -+ if (ret) -+ dev_err(fotg210->dev, "can't bind to phy\n"); -+ } -+ - /* enable device global interrupt */ - value = ioread32(fotg210->reg + FOTG210_DMCR); - value |= DMCR_GLINT_EN; -@@ -1067,6 +1077,9 @@ static int fotg210_udc_stop(struct usb_g - struct fotg210_udc *fotg210 = gadget_to_fotg210(g); - unsigned long flags; - -+ if (!IS_ERR_OR_NULL(fotg210->phy)) -+ return otg_set_peripheral(fotg210->phy->otg, NULL); -+ - spin_lock_irqsave(&fotg210->lock, flags); - - fotg210_init(fotg210); -@@ -1082,12 +1095,50 @@ static const struct usb_gadget_ops fotg2 - .udc_stop = fotg210_udc_stop, - }; - -+/** -+ * fotg210_phy_event - Called by phy upon VBus event -+ * @nb: notifier block -+ * @action: phy action, is vbus connect or disconnect -+ * @data: the usb_gadget structure in fotg210 -+ * -+ * Called by the USB Phy when a cable connect or disconnect is sensed. -+ * -+ * Returns NOTIFY_OK or NOTIFY_DONE -+ */ -+static int fotg210_phy_event(struct notifier_block *nb, unsigned long action, -+ void *data) -+{ -+ struct usb_gadget *gadget = data; -+ -+ if (!gadget) -+ return NOTIFY_DONE; -+ -+ switch (action) { -+ case USB_EVENT_VBUS: -+ usb_gadget_vbus_connect(gadget); -+ return NOTIFY_OK; -+ case USB_EVENT_NONE: -+ usb_gadget_vbus_disconnect(gadget); -+ return NOTIFY_OK; -+ default: -+ return NOTIFY_DONE; -+ } -+} -+ -+static struct notifier_block fotg210_phy_notifier = { -+ .notifier_call = fotg210_phy_event, -+}; -+ - int fotg210_udc_remove(struct platform_device *pdev) - { - struct fotg210_udc *fotg210 = platform_get_drvdata(pdev); - int i; - - usb_del_gadget_udc(&fotg210->gadget); -+ if (!IS_ERR_OR_NULL(fotg210->phy)) { -+ usb_unregister_notifier(fotg210->phy, &fotg210_phy_notifier); -+ usb_put_phy(fotg210->phy); -+ } - iounmap(fotg210->reg); - free_irq(platform_get_irq(pdev, 0), fotg210); - -@@ -1127,6 +1178,22 @@ int fotg210_udc_probe(struct platform_de - if (fotg210 == NULL) - goto err; - -+ fotg210->dev = dev; -+ -+ fotg210->phy = devm_usb_get_phy_by_phandle(dev->parent, "usb-phy", 0); -+ if (IS_ERR(fotg210->phy)) { -+ ret = PTR_ERR(fotg210->phy); -+ if (ret == -EPROBE_DEFER) -+ goto err; -+ dev_info(dev, "no PHY found\n"); -+ fotg210->phy = NULL; -+ } else { -+ ret = usb_phy_init(fotg210->phy); -+ if (ret) -+ goto err; -+ dev_info(dev, "found and initialized PHY\n"); -+ } -+ - for (i = 0; i < FOTG210_MAX_NUM_EP; i++) { - _ep[i] = kzalloc(sizeof(struct fotg210_ep), GFP_KERNEL); - if (_ep[i] == NULL) -@@ -1200,6 +1267,9 @@ int fotg210_udc_probe(struct platform_de - goto err_req; - } - -+ if (!IS_ERR_OR_NULL(fotg210->phy)) -+ usb_register_notifier(fotg210->phy, &fotg210_phy_notifier); -+ - ret = usb_add_gadget_udc(dev, &fotg210->gadget); - if (ret) - goto err_add_udc; -@@ -1209,6 +1279,8 @@ int fotg210_udc_probe(struct platform_de - return 0; - - err_add_udc: -+ if (!IS_ERR_OR_NULL(fotg210->phy)) -+ usb_unregister_notifier(fotg210->phy, &fotg210_phy_notifier); - free_irq(ires->start, fotg210); - - err_req: ---- a/drivers/usb/fotg210/fotg210-udc.h -+++ b/drivers/usb/fotg210/fotg210-udc.h -@@ -234,6 +234,8 @@ struct fotg210_udc { - - unsigned long irq_trigger; - -+ struct device *dev; -+ struct usb_phy *phy; - struct usb_gadget gadget; - struct usb_gadget_driver *driver; - diff --git a/target/linux/gemini/patches-6.1/0010-fotg210-udc-Handle-PCLK.patch b/target/linux/gemini/patches-6.1/0010-fotg210-udc-Handle-PCLK.patch deleted file mode 100644 index 8da3de3b476..00000000000 --- a/target/linux/gemini/patches-6.1/0010-fotg210-udc-Handle-PCLK.patch +++ /dev/null @@ -1,90 +0,0 @@ -From 772ea3ec2b9363b45ef9a4768ea205f758c3debc Mon Sep 17 00:00:00 2001 -From: Linus Walleij -Date: Mon, 14 Nov 2022 12:52:00 +0100 -Subject: [PATCH 10/29] fotg210-udc: Handle PCLK - -This adds optional handling of the peripheral clock PCLK. - -Signed-off-by: Linus Walleij -Link: https://lore.kernel.org/r/20221114115201.302887-3-linus.walleij@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- ---- a/drivers/usb/fotg210/fotg210-udc.c -+++ b/drivers/usb/fotg210/fotg210-udc.c -@@ -15,6 +15,7 @@ - #include - #include - #include -+#include - #include - #include - -@@ -1145,6 +1146,10 @@ int fotg210_udc_remove(struct platform_d - fotg210_ep_free_request(&fotg210->ep[0]->ep, fotg210->ep0_req); - for (i = 0; i < FOTG210_MAX_NUM_EP; i++) - kfree(fotg210->ep[i]); -+ -+ if (!IS_ERR(fotg210->pclk)) -+ clk_disable_unprepare(fotg210->pclk); -+ - kfree(fotg210); - - return 0; -@@ -1180,17 +1185,34 @@ int fotg210_udc_probe(struct platform_de - - fotg210->dev = dev; - -+ /* It's OK not to supply this clock */ -+ fotg210->pclk = devm_clk_get(dev, "PCLK"); -+ if (!IS_ERR(fotg210->pclk)) { -+ ret = clk_prepare_enable(fotg210->pclk); -+ if (ret) { -+ dev_err(dev, "failed to enable PCLK\n"); -+ return ret; -+ } -+ } else if (PTR_ERR(fotg210->pclk) == -EPROBE_DEFER) { -+ /* -+ * Percolate deferrals, for anything else, -+ * just live without the clocking. -+ */ -+ ret = -EPROBE_DEFER; -+ goto err; -+ } -+ - fotg210->phy = devm_usb_get_phy_by_phandle(dev->parent, "usb-phy", 0); - if (IS_ERR(fotg210->phy)) { - ret = PTR_ERR(fotg210->phy); - if (ret == -EPROBE_DEFER) -- goto err; -+ goto err_pclk; - dev_info(dev, "no PHY found\n"); - fotg210->phy = NULL; - } else { - ret = usb_phy_init(fotg210->phy); - if (ret) -- goto err; -+ goto err_pclk; - dev_info(dev, "found and initialized PHY\n"); - } - -@@ -1292,6 +1314,10 @@ err_map: - err_alloc: - for (i = 0; i < FOTG210_MAX_NUM_EP; i++) - kfree(fotg210->ep[i]); -+err_pclk: -+ if (!IS_ERR(fotg210->pclk)) -+ clk_disable_unprepare(fotg210->pclk); -+ - kfree(fotg210); - - err: ---- a/drivers/usb/fotg210/fotg210-udc.h -+++ b/drivers/usb/fotg210/fotg210-udc.h -@@ -231,6 +231,7 @@ struct fotg210_ep { - struct fotg210_udc { - spinlock_t lock; /* protect the struct */ - void __iomem *reg; -+ struct clk *pclk; - - unsigned long irq_trigger; - diff --git a/target/linux/gemini/patches-6.1/0011-fotg210-udc-Get-IRQ-using-platform_get_irq.patch b/target/linux/gemini/patches-6.1/0011-fotg210-udc-Get-IRQ-using-platform_get_irq.patch deleted file mode 100644 index 9544de7cb07..00000000000 --- a/target/linux/gemini/patches-6.1/0011-fotg210-udc-Get-IRQ-using-platform_get_irq.patch +++ /dev/null @@ -1,69 +0,0 @@ -From eda686d41e298a9d16708d2ec8d12d8e682dd7ca Mon Sep 17 00:00:00 2001 -From: Linus Walleij -Date: Mon, 14 Nov 2022 12:52:01 +0100 -Subject: [PATCH 11/29] fotg210-udc: Get IRQ using platform_get_irq() - -The platform_get_irq() is necessary to use to get dynamic -IRQ resolution when instantiating the device from the -device tree. IRQs are not passed as resources in that -case. - -Signed-off-by: Linus Walleij -Link: https://lore.kernel.org/r/20221114115201.302887-4-linus.walleij@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- ---- a/drivers/usb/fotg210/fotg210-udc.c -+++ b/drivers/usb/fotg210/fotg210-udc.c -@@ -1157,10 +1157,11 @@ int fotg210_udc_remove(struct platform_d - - int fotg210_udc_probe(struct platform_device *pdev) - { -- struct resource *res, *ires; -+ struct resource *res; - struct fotg210_udc *fotg210 = NULL; - struct fotg210_ep *_ep[FOTG210_MAX_NUM_EP]; - struct device *dev = &pdev->dev; -+ int irq; - int ret = 0; - int i; - -@@ -1170,9 +1171,9 @@ int fotg210_udc_probe(struct platform_de - return -ENODEV; - } - -- ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0); -- if (!ires) { -- pr_err("platform_get_resource IORESOURCE_IRQ error.\n"); -+ irq = platform_get_irq(pdev, 0); -+ if (irq < 0) { -+ pr_err("could not get irq\n"); - return -ENODEV; - } - -@@ -1202,7 +1203,7 @@ int fotg210_udc_probe(struct platform_de - goto err; - } - -- fotg210->phy = devm_usb_get_phy_by_phandle(dev->parent, "usb-phy", 0); -+ fotg210->phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0); - if (IS_ERR(fotg210->phy)) { - ret = PTR_ERR(fotg210->phy); - if (ret == -EPROBE_DEFER) -@@ -1282,7 +1283,7 @@ int fotg210_udc_probe(struct platform_de - - fotg210_disable_unplug(fotg210); - -- ret = request_irq(ires->start, fotg210_irq, IRQF_SHARED, -+ ret = request_irq(irq, fotg210_irq, IRQF_SHARED, - udc_name, fotg210); - if (ret < 0) { - dev_err(dev, "request_irq error (%d)\n", ret); -@@ -1303,7 +1304,7 @@ int fotg210_udc_probe(struct platform_de - err_add_udc: - if (!IS_ERR_OR_NULL(fotg210->phy)) - usb_unregister_notifier(fotg210->phy, &fotg210_phy_notifier); -- free_irq(ires->start, fotg210); -+ free_irq(irq, fotg210); - - err_req: - fotg210_ep_free_request(&fotg210->ep[0]->ep, fotg210->ep0_req); diff --git a/target/linux/gemini/patches-6.1/0012-usb-fotg210-udc-Remove-a-useless-assignment.patch b/target/linux/gemini/patches-6.1/0012-usb-fotg210-udc-Remove-a-useless-assignment.patch deleted file mode 100644 index 8c33c50b2cb..00000000000 --- a/target/linux/gemini/patches-6.1/0012-usb-fotg210-udc-Remove-a-useless-assignment.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 7889a2f0256c55e0184dffd0001d0782f9e4cb83 Mon Sep 17 00:00:00 2001 -From: Christophe JAILLET -Date: Mon, 14 Nov 2022 21:38:04 +0100 -Subject: [PATCH 12/29] usb: fotg210-udc: Remove a useless assignment - -There is no need to use an intermediate array for these memory allocations, -so, axe it. - -While at it, turn a '== NULL' into a shorter '!' when testing memory -allocation failure. - -Signed-off-by: Christophe JAILLET -Reviewed-by: Linus Walleij -Link: https://lore.kernel.org/r/deab9696fc4000499470e7ccbca7c36fca17bd4e.1668458274.git.christophe.jaillet@wanadoo.fr -Signed-off-by: Greg Kroah-Hartman ---- ---- a/drivers/usb/fotg210/fotg210-udc.c -+++ b/drivers/usb/fotg210/fotg210-udc.c -@@ -1159,7 +1159,6 @@ int fotg210_udc_probe(struct platform_de - { - struct resource *res; - struct fotg210_udc *fotg210 = NULL; -- struct fotg210_ep *_ep[FOTG210_MAX_NUM_EP]; - struct device *dev = &pdev->dev; - int irq; - int ret = 0; -@@ -1218,10 +1217,9 @@ int fotg210_udc_probe(struct platform_de - } - - for (i = 0; i < FOTG210_MAX_NUM_EP; i++) { -- _ep[i] = kzalloc(sizeof(struct fotg210_ep), GFP_KERNEL); -- if (_ep[i] == NULL) -+ fotg210->ep[i] = kzalloc(sizeof(struct fotg210_ep), GFP_KERNEL); -+ if (!fotg210->ep[i]) - goto err_alloc; -- fotg210->ep[i] = _ep[i]; - } - - fotg210->reg = ioremap(res->start, resource_size(res)); diff --git a/target/linux/gemini/patches-6.1/0013-usb-fotg210-udc-fix-potential-memory-leak-in-fotg210.patch b/target/linux/gemini/patches-6.1/0013-usb-fotg210-udc-fix-potential-memory-leak-in-fotg210.patch deleted file mode 100644 index 178135662f5..00000000000 --- a/target/linux/gemini/patches-6.1/0013-usb-fotg210-udc-fix-potential-memory-leak-in-fotg210.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 7b95ade85ac18eec63e81ac58a482b3e88361ffd Mon Sep 17 00:00:00 2001 -From: Yi Yang -Date: Fri, 2 Dec 2022 09:21:26 +0800 -Subject: [PATCH 13/29] usb: fotg210-udc: fix potential memory leak in - fotg210_udc_probe() -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -In fotg210_udc_probe(), if devm_clk_get() or clk_prepare_enable() -fails, 'fotg210' will not be freed, which will lead to a memory leak. -Fix it by moving kfree() to a proper location. - -In addition,we can use "return -ENOMEM" instead of "goto err" -to simplify the code. - -Fixes: 718a38d092ec ("fotg210-udc: Handle PCLK") -Reviewed-by: Andrzej Pietrasiewicz -Reviewed-by: Linus Walleij -Signed-off-by: Yi Yang -Link: https://lore.kernel.org/r/20221202012126.246953-1-yiyang13@huawei.com -Signed-off-by: Greg Kroah-Hartman ---- ---- a/drivers/usb/fotg210/fotg210-udc.c -+++ b/drivers/usb/fotg210/fotg210-udc.c -@@ -1176,12 +1176,10 @@ int fotg210_udc_probe(struct platform_de - return -ENODEV; - } - -- ret = -ENOMEM; -- - /* initialize udc */ - fotg210 = kzalloc(sizeof(struct fotg210_udc), GFP_KERNEL); - if (fotg210 == NULL) -- goto err; -+ return -ENOMEM; - - fotg210->dev = dev; - -@@ -1191,7 +1189,7 @@ int fotg210_udc_probe(struct platform_de - ret = clk_prepare_enable(fotg210->pclk); - if (ret) { - dev_err(dev, "failed to enable PCLK\n"); -- return ret; -+ goto err; - } - } else if (PTR_ERR(fotg210->pclk) == -EPROBE_DEFER) { - /* -@@ -1317,8 +1315,7 @@ err_pclk: - if (!IS_ERR(fotg210->pclk)) - clk_disable_unprepare(fotg210->pclk); - -- kfree(fotg210); -- - err: -+ kfree(fotg210); - return ret; - } diff --git a/target/linux/gemini/patches-6.1/0014-usb-fotg210-fix-OTG-only-build.patch b/target/linux/gemini/patches-6.1/0014-usb-fotg210-fix-OTG-only-build.patch deleted file mode 100644 index acdf1796f3b..00000000000 --- a/target/linux/gemini/patches-6.1/0014-usb-fotg210-fix-OTG-only-build.patch +++ /dev/null @@ -1,39 +0,0 @@ -From d8eed400495029ba551704ff0fae1dad87332291 Mon Sep 17 00:00:00 2001 -From: Arnd Bergmann -Date: Thu, 15 Dec 2022 17:57:20 +0100 -Subject: [PATCH 14/29] usb: fotg210: fix OTG-only build - -The fotg210 module combines the HCD and OTG drivers, which then -fails to build when only the USB gadget support is enabled -in the kernel but host support is not: - -aarch64-linux-ld: drivers/usb/fotg210/fotg210-core.o: in function `fotg210_init': -fotg210-core.c:(.init.text+0xc): undefined reference to `usb_disabled' - -Move the check for usb_disabled() after the check for the HCD module, -and let the OTG driver still be probed in this configuration. - -A nicer approach might be to have the common portion built as a -library module, with the two platform other files registering -their own platform_driver instances separately. - -Fixes: ddacd6ef44ca ("usb: fotg210: Fix Kconfig for USB host modules") -Reviewed-by: Linus Walleij -Signed-off-by: Arnd Bergmann -Link: https://lore.kernel.org/r/20221215165728.2062984-1-arnd@kernel.org -Signed-off-by: Greg Kroah-Hartman ---- ---- a/drivers/usb/fotg210/fotg210-core.c -+++ b/drivers/usb/fotg210/fotg210-core.c -@@ -144,10 +144,7 @@ static struct platform_driver fotg210_dr - - static int __init fotg210_init(void) - { -- if (usb_disabled()) -- return -ENODEV; -- -- if (IS_ENABLED(CONFIG_USB_FOTG210_HCD)) -+ if (IS_ENABLED(CONFIG_USB_FOTG210_HCD) && !usb_disabled()) - fotg210_hcd_init(); - return platform_driver_register(&fotg210_driver); - } diff --git a/target/linux/gemini/patches-6.1/0015-usb-fotg210-udc-fix-error-return-code-in-fotg210_udc.patch b/target/linux/gemini/patches-6.1/0015-usb-fotg210-udc-fix-error-return-code-in-fotg210_udc.patch deleted file mode 100644 index a9bbca58b4a..00000000000 --- a/target/linux/gemini/patches-6.1/0015-usb-fotg210-udc-fix-error-return-code-in-fotg210_udc.patch +++ /dev/null @@ -1,28 +0,0 @@ -From eaaa85d907fe27852dd960b2bc5d7bcf11bc3ebd Mon Sep 17 00:00:00 2001 -From: Yang Yingliang -Date: Fri, 30 Dec 2022 14:54:27 +0800 -Subject: [PATCH 15/29] usb: fotg210-udc: fix error return code in - fotg210_udc_probe() - -After commit 5f217ccd520f ("fotg210-udc: Support optional external PHY"), -the error code is re-assigned to 0 in fotg210_udc_probe(), if allocate or -map memory fails after the assignment, it can't return an error code. Set -the error code to -ENOMEM to fix this problem. - -Fixes: 5f217ccd520f ("fotg210-udc: Support optional external PHY") -Signed-off-by: Yang Yingliang -Reviewed-by: Linus Walleij -Link: https://lore.kernel.org/r/20221230065427.944586-1-yangyingliang@huawei.com -Signed-off-by: Greg Kroah-Hartman ---- ---- a/drivers/usb/fotg210/fotg210-udc.c -+++ b/drivers/usb/fotg210/fotg210-udc.c -@@ -1214,6 +1214,8 @@ int fotg210_udc_probe(struct platform_de - dev_info(dev, "found and initialized PHY\n"); - } - -+ ret = -ENOMEM; -+ - for (i = 0; i < FOTG210_MAX_NUM_EP; i++) { - fotg210->ep[i] = kzalloc(sizeof(struct fotg210_ep), GFP_KERNEL); - if (!fotg210->ep[i]) diff --git a/target/linux/gemini/patches-6.1/0016-usb-fotg210-List-different-variants.patch b/target/linux/gemini/patches-6.1/0016-usb-fotg210-List-different-variants.patch deleted file mode 100644 index 6ff6d28ad3f..00000000000 --- a/target/linux/gemini/patches-6.1/0016-usb-fotg210-List-different-variants.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 407577548b2fcd41cc72ee05df1f05a430ed30a0 Mon Sep 17 00:00:00 2001 -From: Linus Walleij -Date: Wed, 18 Jan 2023 08:09:16 +0100 -Subject: [PATCH 16/29] usb: fotg210: List different variants - -There are at least two variants of the FOTG: FOTG200 and -FOTG210. Handle them in this driver and let's add -more quirks as we go along. - -Signed-off-by: Linus Walleij -Link: https://lore.kernel.org/r/20230103-gemini-fotg210-usb-v2-2-100388af9810@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- ---- a/drivers/usb/fotg210/fotg210-core.c -+++ b/drivers/usb/fotg210/fotg210-core.c -@@ -127,7 +127,9 @@ static int fotg210_remove(struct platfor - - #ifdef CONFIG_OF - static const struct of_device_id fotg210_of_match[] = { -+ { .compatible = "faraday,fotg200" }, - { .compatible = "faraday,fotg210" }, -+ /* TODO: can we also handle FUSB220? */ - {}, - }; - MODULE_DEVICE_TABLE(of, fotg210_of_match); diff --git a/target/linux/gemini/patches-6.1/0017-usb-fotg210-Acquire-memory-resource-in-core.patch b/target/linux/gemini/patches-6.1/0017-usb-fotg210-Acquire-memory-resource-in-core.patch deleted file mode 100644 index 7dbd511ecbe..00000000000 --- a/target/linux/gemini/patches-6.1/0017-usb-fotg210-Acquire-memory-resource-in-core.patch +++ /dev/null @@ -1,245 +0,0 @@ -From fa735ad1afeb5791d5562617b9bbed74574d3e81 Mon Sep 17 00:00:00 2001 -From: Linus Walleij -Date: Wed, 18 Jan 2023 08:09:17 +0100 -Subject: [PATCH 17/29] usb: fotg210: Acquire memory resource in core - -The subdrivers are obtaining and mapping the memory resource -separately. Create a common state container for the shared -resources and start populating this by acquiring the IO -memory resource and remap it and pass this to the subdrivers -for host and peripheral. - -Signed-off-by: Linus Walleij -Link: https://lore.kernel.org/r/20230103-gemini-fotg210-usb-v2-3-100388af9810@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- ---- a/drivers/usb/fotg210/fotg210-core.c -+++ b/drivers/usb/fotg210/fotg210-core.c -@@ -33,9 +33,10 @@ - #define GEMINI_MISC_USB0_MINI_B BIT(29) - #define GEMINI_MISC_USB1_MINI_B BIT(30) - --static int fotg210_gemini_init(struct device *dev, struct resource *res, -+static int fotg210_gemini_init(struct fotg210 *fotg, struct resource *res, - enum usb_dr_mode mode) - { -+ struct device *dev = fotg->dev; - struct device_node *np = dev->of_node; - struct regmap *map; - bool wakeup; -@@ -47,6 +48,7 @@ static int fotg210_gemini_init(struct de - dev_err(dev, "no syscon\n"); - return PTR_ERR(map); - } -+ fotg->map = map; - wakeup = of_property_read_bool(np, "wakeup-source"); - - /* -@@ -55,6 +57,7 @@ static int fotg210_gemini_init(struct de - */ - mask = 0; - if (res->start == 0x69000000) { -+ fotg->port = GEMINI_PORT_1; - mask = GEMINI_MISC_USB1_VBUS_ON | GEMINI_MISC_USB1_MINI_B | - GEMINI_MISC_USB1_WAKEUP; - if (mode == USB_DR_MODE_HOST) -@@ -64,6 +67,7 @@ static int fotg210_gemini_init(struct de - if (wakeup) - val |= GEMINI_MISC_USB1_WAKEUP; - } else { -+ fotg->port = GEMINI_PORT_0; - mask = GEMINI_MISC_USB0_VBUS_ON | GEMINI_MISC_USB0_MINI_B | - GEMINI_MISC_USB0_WAKEUP; - if (mode == USB_DR_MODE_HOST) -@@ -89,23 +93,34 @@ static int fotg210_probe(struct platform - { - struct device *dev = &pdev->dev; - enum usb_dr_mode mode; -+ struct fotg210 *fotg; - int ret; - -+ fotg = devm_kzalloc(dev, sizeof(*fotg), GFP_KERNEL); -+ if (!fotg) -+ return -ENOMEM; -+ fotg->dev = dev; -+ -+ fotg->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (!fotg->res) -+ return -ENODEV; -+ -+ fotg->base = devm_ioremap_resource(dev, fotg->res); -+ if (!fotg->base) -+ return -ENOMEM; -+ - mode = usb_get_dr_mode(dev); - - if (of_device_is_compatible(dev->of_node, "cortina,gemini-usb")) { -- struct resource *res; -- -- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -- ret = fotg210_gemini_init(dev, res, mode); -+ ret = fotg210_gemini_init(fotg, fotg->res, mode); - if (ret) - return ret; - } - - if (mode == USB_DR_MODE_PERIPHERAL) -- ret = fotg210_udc_probe(pdev); -+ ret = fotg210_udc_probe(pdev, fotg); - else -- ret = fotg210_hcd_probe(pdev); -+ ret = fotg210_hcd_probe(pdev, fotg); - - return ret; - } ---- a/drivers/usb/fotg210/fotg210-hcd.c -+++ b/drivers/usb/fotg210/fotg210-hcd.c -@@ -5557,11 +5557,10 @@ static void fotg210_init(struct fotg210_ - * then invokes the start() method for the HCD associated with it - * through the hotplug entry's driver_data. - */ --int fotg210_hcd_probe(struct platform_device *pdev) -+int fotg210_hcd_probe(struct platform_device *pdev, struct fotg210 *fotg) - { - struct device *dev = &pdev->dev; - struct usb_hcd *hcd; -- struct resource *res; - int irq; - int retval; - struct fotg210_hcd *fotg210; -@@ -5585,18 +5584,14 @@ int fotg210_hcd_probe(struct platform_de - - hcd->has_tt = 1; - -- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -- hcd->regs = devm_ioremap_resource(&pdev->dev, res); -- if (IS_ERR(hcd->regs)) { -- retval = PTR_ERR(hcd->regs); -- goto failed_put_hcd; -- } -+ hcd->regs = fotg->base; - -- hcd->rsrc_start = res->start; -- hcd->rsrc_len = resource_size(res); -+ hcd->rsrc_start = fotg->res->start; -+ hcd->rsrc_len = resource_size(fotg->res); - - fotg210 = hcd_to_fotg210(hcd); - -+ fotg210->fotg = fotg; - fotg210->caps = hcd->regs; - - /* It's OK not to supply this clock */ ---- a/drivers/usb/fotg210/fotg210-hcd.h -+++ b/drivers/usb/fotg210/fotg210-hcd.h -@@ -182,6 +182,7 @@ struct fotg210_hcd { /* one per contro - # define INCR(x) do {} while (0) - #endif - -+ struct fotg210 *fotg; /* Overarching FOTG210 device */ - /* silicon clock */ - struct clk *pclk; - }; ---- a/drivers/usb/fotg210/fotg210-udc.c -+++ b/drivers/usb/fotg210/fotg210-udc.c -@@ -1155,21 +1155,14 @@ int fotg210_udc_remove(struct platform_d - return 0; - } - --int fotg210_udc_probe(struct platform_device *pdev) -+int fotg210_udc_probe(struct platform_device *pdev, struct fotg210 *fotg) - { -- struct resource *res; - struct fotg210_udc *fotg210 = NULL; - struct device *dev = &pdev->dev; - int irq; - int ret = 0; - int i; - -- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -- if (!res) { -- pr_err("platform_get_resource error.\n"); -- return -ENODEV; -- } -- - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - pr_err("could not get irq\n"); -@@ -1182,6 +1175,7 @@ int fotg210_udc_probe(struct platform_de - return -ENOMEM; - - fotg210->dev = dev; -+ fotg210->fotg = fotg; - - /* It's OK not to supply this clock */ - fotg210->pclk = devm_clk_get(dev, "PCLK"); -@@ -1222,11 +1216,7 @@ int fotg210_udc_probe(struct platform_de - goto err_alloc; - } - -- fotg210->reg = ioremap(res->start, resource_size(res)); -- if (fotg210->reg == NULL) { -- dev_err(dev, "ioremap error\n"); -- goto err_alloc; -- } -+ fotg210->reg = fotg->base; - - spin_lock_init(&fotg210->lock); - ---- a/drivers/usb/fotg210/fotg210-udc.h -+++ b/drivers/usb/fotg210/fotg210-udc.h -@@ -236,6 +236,7 @@ struct fotg210_udc { - unsigned long irq_trigger; - - struct device *dev; -+ struct fotg210 *fotg; - struct usb_phy *phy; - struct usb_gadget gadget; - struct usb_gadget_driver *driver; ---- a/drivers/usb/fotg210/fotg210.h -+++ b/drivers/usb/fotg210/fotg210.h -@@ -2,13 +2,28 @@ - #ifndef __FOTG210_H - #define __FOTG210_H - -+enum gemini_port { -+ GEMINI_PORT_NONE = 0, -+ GEMINI_PORT_0, -+ GEMINI_PORT_1, -+}; -+ -+struct fotg210 { -+ struct device *dev; -+ struct resource *res; -+ void __iomem *base; -+ struct regmap *map; -+ enum gemini_port port; -+}; -+ - #ifdef CONFIG_USB_FOTG210_HCD --int fotg210_hcd_probe(struct platform_device *pdev); -+int fotg210_hcd_probe(struct platform_device *pdev, struct fotg210 *fotg); - int fotg210_hcd_remove(struct platform_device *pdev); - int fotg210_hcd_init(void); - void fotg210_hcd_cleanup(void); - #else --static inline int fotg210_hcd_probe(struct platform_device *pdev) -+static inline int fotg210_hcd_probe(struct platform_device *pdev, -+ struct fotg210 *fotg) - { - return 0; - } -@@ -26,10 +41,11 @@ static inline void fotg210_hcd_cleanup(v - #endif - - #ifdef CONFIG_USB_FOTG210_UDC --int fotg210_udc_probe(struct platform_device *pdev); -+int fotg210_udc_probe(struct platform_device *pdev, struct fotg210 *fotg); - int fotg210_udc_remove(struct platform_device *pdev); - #else --static inline int fotg210_udc_probe(struct platform_device *pdev) -+static inline int fotg210_udc_probe(struct platform_device *pdev, -+ struct fotg210 *fotg) - { - return 0; - } diff --git a/target/linux/gemini/patches-6.1/0018-usb-fotg210-Move-clock-handling-to-core.patch b/target/linux/gemini/patches-6.1/0018-usb-fotg210-Move-clock-handling-to-core.patch deleted file mode 100644 index 9894f4dc66d..00000000000 --- a/target/linux/gemini/patches-6.1/0018-usb-fotg210-Move-clock-handling-to-core.patch +++ /dev/null @@ -1,196 +0,0 @@ -From fb8e1e8dbc47e7aff7624b47adaa0a84d2983802 Mon Sep 17 00:00:00 2001 -From: Linus Walleij -Date: Wed, 18 Jan 2023 08:09:18 +0100 -Subject: [PATCH 18/29] usb: fotg210: Move clock handling to core - -Grab the optional silicon block clock, prepare and enable it in -the core before proceeding to prepare the host or peripheral -driver. This saves duplicate code and also uses the simple -devm_clk_get_optional_enabled() to do everything we really -want to do. - -Signed-off-by: Linus Walleij -Link: https://lore.kernel.org/r/20230103-gemini-fotg210-usb-v2-4-100388af9810@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- ---- a/drivers/usb/fotg210/fotg210-core.c -+++ b/drivers/usb/fotg210/fotg210-core.c -@@ -6,6 +6,7 @@ - * driver. - */ - #include -+#include - #include - #include - #include -@@ -109,6 +110,10 @@ static int fotg210_probe(struct platform - if (!fotg->base) - return -ENOMEM; - -+ fotg->pclk = devm_clk_get_optional_enabled(dev, "PCLK"); -+ if (IS_ERR(fotg->pclk)) -+ return PTR_ERR(fotg->pclk); -+ - mode = usb_get_dr_mode(dev); - - if (of_device_is_compatible(dev->of_node, "cortina,gemini-usb")) { ---- a/drivers/usb/fotg210/fotg210-hcd.c -+++ b/drivers/usb/fotg210/fotg210-hcd.c -@@ -33,7 +33,6 @@ - #include - #include - #include --#include - - #include - #include -@@ -5594,44 +5593,22 @@ int fotg210_hcd_probe(struct platform_de - fotg210->fotg = fotg; - fotg210->caps = hcd->regs; - -- /* It's OK not to supply this clock */ -- fotg210->pclk = clk_get(dev, "PCLK"); -- if (!IS_ERR(fotg210->pclk)) { -- retval = clk_prepare_enable(fotg210->pclk); -- if (retval) { -- dev_err(dev, "failed to enable PCLK\n"); -- goto failed_put_hcd; -- } -- } else if (PTR_ERR(fotg210->pclk) == -EPROBE_DEFER) { -- /* -- * Percolate deferrals, for anything else, -- * just live without the clocking. -- */ -- retval = PTR_ERR(fotg210->pclk); -- goto failed_dis_clk; -- } -- - retval = fotg210_setup(hcd); - if (retval) -- goto failed_dis_clk; -+ goto failed_put_hcd; - - fotg210_init(fotg210); - - retval = usb_add_hcd(hcd, irq, IRQF_SHARED); - if (retval) { - dev_err(dev, "failed to add hcd with err %d\n", retval); -- goto failed_dis_clk; -+ goto failed_put_hcd; - } - device_wakeup_enable(hcd->self.controller); - platform_set_drvdata(pdev, hcd); - - return retval; - --failed_dis_clk: -- if (!IS_ERR(fotg210->pclk)) { -- clk_disable_unprepare(fotg210->pclk); -- clk_put(fotg210->pclk); -- } - failed_put_hcd: - usb_put_hcd(hcd); - fail_create_hcd: -@@ -5647,12 +5624,6 @@ fail_create_hcd: - int fotg210_hcd_remove(struct platform_device *pdev) - { - struct usb_hcd *hcd = platform_get_drvdata(pdev); -- struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); -- -- if (!IS_ERR(fotg210->pclk)) { -- clk_disable_unprepare(fotg210->pclk); -- clk_put(fotg210->pclk); -- } - - usb_remove_hcd(hcd); - usb_put_hcd(hcd); ---- a/drivers/usb/fotg210/fotg210-udc.c -+++ b/drivers/usb/fotg210/fotg210-udc.c -@@ -15,7 +15,6 @@ - #include - #include - #include --#include - #include - #include - -@@ -1147,9 +1146,6 @@ int fotg210_udc_remove(struct platform_d - for (i = 0; i < FOTG210_MAX_NUM_EP; i++) - kfree(fotg210->ep[i]); - -- if (!IS_ERR(fotg210->pclk)) -- clk_disable_unprepare(fotg210->pclk); -- - kfree(fotg210); - - return 0; -@@ -1177,34 +1173,17 @@ int fotg210_udc_probe(struct platform_de - fotg210->dev = dev; - fotg210->fotg = fotg; - -- /* It's OK not to supply this clock */ -- fotg210->pclk = devm_clk_get(dev, "PCLK"); -- if (!IS_ERR(fotg210->pclk)) { -- ret = clk_prepare_enable(fotg210->pclk); -- if (ret) { -- dev_err(dev, "failed to enable PCLK\n"); -- goto err; -- } -- } else if (PTR_ERR(fotg210->pclk) == -EPROBE_DEFER) { -- /* -- * Percolate deferrals, for anything else, -- * just live without the clocking. -- */ -- ret = -EPROBE_DEFER; -- goto err; -- } -- - fotg210->phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0); - if (IS_ERR(fotg210->phy)) { - ret = PTR_ERR(fotg210->phy); - if (ret == -EPROBE_DEFER) -- goto err_pclk; -+ goto err_free; - dev_info(dev, "no PHY found\n"); - fotg210->phy = NULL; - } else { - ret = usb_phy_init(fotg210->phy); - if (ret) -- goto err_pclk; -+ goto err_free; - dev_info(dev, "found and initialized PHY\n"); - } - -@@ -1303,11 +1282,8 @@ err_map: - err_alloc: - for (i = 0; i < FOTG210_MAX_NUM_EP; i++) - kfree(fotg210->ep[i]); --err_pclk: -- if (!IS_ERR(fotg210->pclk)) -- clk_disable_unprepare(fotg210->pclk); - --err: -+err_free: - kfree(fotg210); - return ret; - } ---- a/drivers/usb/fotg210/fotg210-udc.h -+++ b/drivers/usb/fotg210/fotg210-udc.h -@@ -231,7 +231,6 @@ struct fotg210_ep { - struct fotg210_udc { - spinlock_t lock; /* protect the struct */ - void __iomem *reg; -- struct clk *pclk; - - unsigned long irq_trigger; - ---- a/drivers/usb/fotg210/fotg210.h -+++ b/drivers/usb/fotg210/fotg210.h -@@ -12,6 +12,7 @@ struct fotg210 { - struct device *dev; - struct resource *res; - void __iomem *base; -+ struct clk *pclk; - struct regmap *map; - enum gemini_port port; - }; diff --git a/target/linux/gemini/patches-6.1/0019-usb-fotg210-Check-role-register-in-core.patch b/target/linux/gemini/patches-6.1/0019-usb-fotg210-Check-role-register-in-core.patch deleted file mode 100644 index 892b0d31af0..00000000000 --- a/target/linux/gemini/patches-6.1/0019-usb-fotg210-Check-role-register-in-core.patch +++ /dev/null @@ -1,54 +0,0 @@ -From b1b07abb598211de3ce7f52abdf8dcb24384341e Mon Sep 17 00:00:00 2001 -From: Linus Walleij -Date: Wed, 18 Jan 2023 08:09:19 +0100 -Subject: [PATCH 19/29] usb: fotg210: Check role register in core - -Read the role register and check that we are in host/peripheral -mode and issue warnings if we're not in the right role when -probing respective driver. - -Signed-off-by: Linus Walleij -Link: https://lore.kernel.org/r/20230103-gemini-fotg210-usb-v2-5-100388af9810@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- ---- a/drivers/usb/fotg210/fotg210-core.c -+++ b/drivers/usb/fotg210/fotg210-core.c -@@ -18,6 +18,11 @@ - - #include "fotg210.h" - -+/* Role Register 0x80 */ -+#define FOTG210_RR 0x80 -+#define FOTG210_RR_ID BIT(21) /* 1 = B-device, 0 = A-device */ -+#define FOTG210_RR_CROLE BIT(20) /* 1 = device, 0 = host */ -+ - /* - * Gemini-specific initialization function, only executed on the - * Gemini SoC using the global misc control register. -@@ -95,6 +100,7 @@ static int fotg210_probe(struct platform - struct device *dev = &pdev->dev; - enum usb_dr_mode mode; - struct fotg210 *fotg; -+ u32 val; - int ret; - - fotg = devm_kzalloc(dev, sizeof(*fotg), GFP_KERNEL); -@@ -122,10 +128,16 @@ static int fotg210_probe(struct platform - return ret; - } - -- if (mode == USB_DR_MODE_PERIPHERAL) -+ val = readl(fotg->base + FOTG210_RR); -+ if (mode == USB_DR_MODE_PERIPHERAL) { -+ if (!(val & FOTG210_RR_CROLE)) -+ dev_err(dev, "block not in device role\n"); - ret = fotg210_udc_probe(pdev, fotg); -- else -+ } else { -+ if (val & FOTG210_RR_CROLE) -+ dev_err(dev, "block not in host role\n"); - ret = fotg210_hcd_probe(pdev, fotg); -+ } - - return ret; - } diff --git a/target/linux/gemini/patches-6.1/0020-usb-fotg210-udc-Assign-of_node-and-speed-on-start.patch b/target/linux/gemini/patches-6.1/0020-usb-fotg210-udc-Assign-of_node-and-speed-on-start.patch deleted file mode 100644 index 20f8f943501..00000000000 --- a/target/linux/gemini/patches-6.1/0020-usb-fotg210-udc-Assign-of_node-and-speed-on-start.patch +++ /dev/null @@ -1,34 +0,0 @@ -From d7c2b0b6da75b86cf5ddbcd51a74d74e19bbf178 Mon Sep 17 00:00:00 2001 -From: Linus Walleij -Date: Wed, 18 Jan 2023 08:09:20 +0100 -Subject: [PATCH 20/29] usb: fotg210-udc: Assign of_node and speed on start - -Follow the example set by other drivers to assign of_node -and speed to the driver when binding, also print bound -info akin to other UDC drivers. - -Signed-off-by: Linus Walleij -Link: https://lore.kernel.org/r/20230103-gemini-fotg210-usb-v2-6-100388af9810@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- ---- a/drivers/usb/fotg210/fotg210-udc.c -+++ b/drivers/usb/fotg210/fotg210-udc.c -@@ -1028,6 +1028,10 @@ static int fotg210_udc_start(struct usb_ - - /* hook up the driver */ - fotg210->driver = driver; -+ fotg210->gadget.dev.of_node = fotg210->dev->of_node; -+ fotg210->gadget.speed = USB_SPEED_UNKNOWN; -+ -+ dev_info(fotg210->dev, "bound driver %s\n", driver->driver.name); - - if (!IS_ERR_OR_NULL(fotg210->phy)) { - ret = otg_set_peripheral(fotg210->phy->otg, -@@ -1084,6 +1088,7 @@ static int fotg210_udc_stop(struct usb_g - - fotg210_init(fotg210); - fotg210->driver = NULL; -+ fotg210->gadget.speed = USB_SPEED_UNKNOWN; - - spin_unlock_irqrestore(&fotg210->lock, flags); - diff --git a/target/linux/gemini/patches-6.1/0021-usb-fotg210-udc-Implement-VBUS-session.patch b/target/linux/gemini/patches-6.1/0021-usb-fotg210-udc-Implement-VBUS-session.patch deleted file mode 100644 index d98561f0d4c..00000000000 --- a/target/linux/gemini/patches-6.1/0021-usb-fotg210-udc-Implement-VBUS-session.patch +++ /dev/null @@ -1,96 +0,0 @@ -From 2fbbfb2c556944945639b17b13fcb1e05272b646 Mon Sep 17 00:00:00 2001 -From: Linus Walleij -Date: Wed, 18 Jan 2023 08:09:21 +0100 -Subject: [PATCH 21/29] usb: fotg210-udc: Implement VBUS session - -Implement VBUS session handling for FOTG210. This is -mainly used by the UDC driver which needs to call down to -the FOTG210 core and enable/disable VBUS, as this needs to be -handled outside of the HCD and UDC drivers, by platform -specific glue code. - -The Gemini has a special bit in a system register to turn -VBUS on and off so we implement this in the FOTG210 core. - -Signed-off-by: Linus Walleij -Link: https://lore.kernel.org/r/20230103-gemini-fotg210-usb-v2-7-100388af9810@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- ---- a/drivers/usb/fotg210/fotg210-core.c -+++ b/drivers/usb/fotg210/fotg210-core.c -@@ -95,6 +95,35 @@ static int fotg210_gemini_init(struct fo - return 0; - } - -+/** -+ * fotg210_vbus() - Called by gadget driver to enable/disable VBUS -+ * @enable: true to enable VBUS, false to disable VBUS -+ */ -+void fotg210_vbus(struct fotg210 *fotg, bool enable) -+{ -+ u32 mask; -+ u32 val; -+ int ret; -+ -+ switch (fotg->port) { -+ case GEMINI_PORT_0: -+ mask = GEMINI_MISC_USB0_VBUS_ON; -+ val = enable ? GEMINI_MISC_USB0_VBUS_ON : 0; -+ break; -+ case GEMINI_PORT_1: -+ mask = GEMINI_MISC_USB1_VBUS_ON; -+ val = enable ? GEMINI_MISC_USB1_VBUS_ON : 0; -+ break; -+ default: -+ return; -+ } -+ ret = regmap_update_bits(fotg->map, GEMINI_GLOBAL_MISC_CTRL, mask, val); -+ if (ret) -+ dev_err(fotg->dev, "failed to %s VBUS\n", -+ enable ? "enable" : "disable"); -+ dev_info(fotg->dev, "%s: %s VBUS\n", __func__, enable ? "enable" : "disable"); -+} -+ - static int fotg210_probe(struct platform_device *pdev) - { - struct device *dev = &pdev->dev; ---- a/drivers/usb/fotg210/fotg210-udc.c -+++ b/drivers/usb/fotg210/fotg210-udc.c -@@ -1095,9 +1095,26 @@ static int fotg210_udc_stop(struct usb_g - return 0; - } - -+/** -+ * fotg210_vbus_session - Called by external transceiver to enable/disable udc -+ * @_gadget: usb gadget -+ * @is_active: 0 if should disable UDC VBUS, 1 if should enable -+ * -+ * Returns 0 -+ */ -+static int fotg210_vbus_session(struct usb_gadget *g, int is_active) -+{ -+ struct fotg210_udc *fotg210 = gadget_to_fotg210(g); -+ -+ /* Call down to core integration layer to drive or disable VBUS */ -+ fotg210_vbus(fotg210->fotg, is_active); -+ return 0; -+} -+ - static const struct usb_gadget_ops fotg210_gadget_ops = { - .udc_start = fotg210_udc_start, - .udc_stop = fotg210_udc_stop, -+ .vbus_session = fotg210_vbus_session, - }; - - /** ---- a/drivers/usb/fotg210/fotg210.h -+++ b/drivers/usb/fotg210/fotg210.h -@@ -17,6 +17,8 @@ struct fotg210 { - enum gemini_port port; - }; - -+void fotg210_vbus(struct fotg210 *fotg, bool enable); -+ - #ifdef CONFIG_USB_FOTG210_HCD - int fotg210_hcd_probe(struct platform_device *pdev, struct fotg210 *fotg); - int fotg210_hcd_remove(struct platform_device *pdev); diff --git a/target/linux/gemini/patches-6.1/0022-fotg210-udc-Introduce-and-use-a-fotg210_ack_int-func.patch b/target/linux/gemini/patches-6.1/0022-fotg210-udc-Introduce-and-use-a-fotg210_ack_int-func.patch deleted file mode 100644 index fc5831eb23b..00000000000 --- a/target/linux/gemini/patches-6.1/0022-fotg210-udc-Introduce-and-use-a-fotg210_ack_int-func.patch +++ /dev/null @@ -1,134 +0,0 @@ -From f011d1eab23f4c063c5441c0d5a22898adf9145c Mon Sep 17 00:00:00 2001 -From: Fabian Vogt -Date: Mon, 23 Jan 2023 08:35:07 +0100 -Subject: [PATCH 22/29] fotg210-udc: Introduce and use a fotg210_ack_int - function - -This is in preparation of support for devices where interrupts are acked -differently. - -Signed-off-by: Fabian Vogt -Signed-off-by: Linus Walleij -Link: https://lore.kernel.org/r/20230123073508.2350402-3-linus.walleij@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- ---- a/drivers/usb/fotg210/fotg210-udc.c -+++ b/drivers/usb/fotg210/fotg210-udc.c -@@ -28,6 +28,14 @@ static const char udc_name[] = "fotg210_ - static const char * const fotg210_ep_name[] = { - "ep0", "ep1", "ep2", "ep3", "ep4"}; - -+static void fotg210_ack_int(struct fotg210_udc *fotg210, u32 offset, u32 mask) -+{ -+ u32 value = ioread32(fotg210->reg + offset); -+ -+ value &= ~mask; -+ iowrite32(value, fotg210->reg + offset); -+} -+ - static void fotg210_disable_fifo_int(struct fotg210_ep *ep) - { - u32 value = ioread32(ep->fotg210->reg + FOTG210_DMISGR1); -@@ -303,8 +311,7 @@ static void fotg210_wait_dma_done(struct - goto dma_reset; - } while (!(value & DISGR2_DMA_CMPLT)); - -- value &= ~DISGR2_DMA_CMPLT; -- iowrite32(value, ep->fotg210->reg + FOTG210_DISGR2); -+ fotg210_ack_int(ep->fotg210, FOTG210_DISGR2, DISGR2_DMA_CMPLT); - return; - - dma_reset: -@@ -844,14 +851,6 @@ static void fotg210_ep0in(struct fotg210 - } - } - --static void fotg210_clear_comabt_int(struct fotg210_udc *fotg210) --{ -- u32 value = ioread32(fotg210->reg + FOTG210_DISGR0); -- -- value &= ~DISGR0_CX_COMABT_INT; -- iowrite32(value, fotg210->reg + FOTG210_DISGR0); --} -- - static void fotg210_in_fifo_handler(struct fotg210_ep *ep) - { - struct fotg210_request *req = list_entry(ep->queue.next, -@@ -893,60 +892,43 @@ static irqreturn_t fotg210_irq(int irq, - void __iomem *reg = fotg210->reg + FOTG210_DISGR2; - u32 int_grp2 = ioread32(reg); - u32 int_msk2 = ioread32(fotg210->reg + FOTG210_DMISGR2); -- u32 value; - - int_grp2 &= ~int_msk2; - - if (int_grp2 & DISGR2_USBRST_INT) { - usb_gadget_udc_reset(&fotg210->gadget, - fotg210->driver); -- value = ioread32(reg); -- value &= ~DISGR2_USBRST_INT; -- iowrite32(value, reg); -+ fotg210_ack_int(fotg210, FOTG210_DISGR2, DISGR2_USBRST_INT); - pr_info("fotg210 udc reset\n"); - } - if (int_grp2 & DISGR2_SUSP_INT) { -- value = ioread32(reg); -- value &= ~DISGR2_SUSP_INT; -- iowrite32(value, reg); -+ fotg210_ack_int(fotg210, FOTG210_DISGR2, DISGR2_SUSP_INT); - pr_info("fotg210 udc suspend\n"); - } - if (int_grp2 & DISGR2_RESM_INT) { -- value = ioread32(reg); -- value &= ~DISGR2_RESM_INT; -- iowrite32(value, reg); -+ fotg210_ack_int(fotg210, FOTG210_DISGR2, DISGR2_RESM_INT); - pr_info("fotg210 udc resume\n"); - } - if (int_grp2 & DISGR2_ISO_SEQ_ERR_INT) { -- value = ioread32(reg); -- value &= ~DISGR2_ISO_SEQ_ERR_INT; -- iowrite32(value, reg); -+ fotg210_ack_int(fotg210, FOTG210_DISGR2, DISGR2_ISO_SEQ_ERR_INT); - pr_info("fotg210 iso sequence error\n"); - } - if (int_grp2 & DISGR2_ISO_SEQ_ABORT_INT) { -- value = ioread32(reg); -- value &= ~DISGR2_ISO_SEQ_ABORT_INT; -- iowrite32(value, reg); -+ fotg210_ack_int(fotg210, FOTG210_DISGR2, DISGR2_ISO_SEQ_ABORT_INT); - pr_info("fotg210 iso sequence abort\n"); - } - if (int_grp2 & DISGR2_TX0BYTE_INT) { - fotg210_clear_tx0byte(fotg210); -- value = ioread32(reg); -- value &= ~DISGR2_TX0BYTE_INT; -- iowrite32(value, reg); -+ fotg210_ack_int(fotg210, FOTG210_DISGR2, DISGR2_TX0BYTE_INT); - pr_info("fotg210 transferred 0 byte\n"); - } - if (int_grp2 & DISGR2_RX0BYTE_INT) { - fotg210_clear_rx0byte(fotg210); -- value = ioread32(reg); -- value &= ~DISGR2_RX0BYTE_INT; -- iowrite32(value, reg); -+ fotg210_ack_int(fotg210, FOTG210_DISGR2, DISGR2_RX0BYTE_INT); - pr_info("fotg210 received 0 byte\n"); - } - if (int_grp2 & DISGR2_DMA_ERROR) { -- value = ioread32(reg); -- value &= ~DISGR2_DMA_ERROR; -- iowrite32(value, reg); -+ fotg210_ack_int(fotg210, FOTG210_DISGR2, DISGR2_DMA_ERROR); - } - } - -@@ -960,7 +942,7 @@ static irqreturn_t fotg210_irq(int irq, - - /* the highest priority in this source register */ - if (int_grp0 & DISGR0_CX_COMABT_INT) { -- fotg210_clear_comabt_int(fotg210); -+ fotg210_ack_int(fotg210, FOTG210_DISGR0, DISGR0_CX_COMABT_INT); - pr_info("fotg210 CX command abort\n"); - } - diff --git a/target/linux/gemini/patches-6.1/0023-fotg210-udc-Improve-device-initialization.patch b/target/linux/gemini/patches-6.1/0023-fotg210-udc-Improve-device-initialization.patch deleted file mode 100644 index fde17a48b3d..00000000000 --- a/target/linux/gemini/patches-6.1/0023-fotg210-udc-Improve-device-initialization.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 367747c7813cecf19b46ef7134691f903ab76dc9 Mon Sep 17 00:00:00 2001 -From: Fabian Vogt -Date: Mon, 23 Jan 2023 08:35:08 +0100 -Subject: [PATCH 23/29] fotg210-udc: Improve device initialization - -Reset the device explicitly to get into a known state and also set the chip -enable bit. Additionally, mask interrupts which aren't handled. - -Signed-off-by: Fabian Vogt -Signed-off-by: Linus Walleij -Link: https://lore.kernel.org/r/20230123073508.2350402-4-linus.walleij@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- ---- a/drivers/usb/fotg210/fotg210-udc.c -+++ b/drivers/usb/fotg210/fotg210-udc.c -@@ -7,6 +7,7 @@ - * Author : Yuan-Hsin Chen - */ - -+#include - #include - #include - #include -@@ -1022,6 +1023,11 @@ static int fotg210_udc_start(struct usb_ - dev_err(fotg210->dev, "can't bind to phy\n"); - } - -+ /* chip enable */ -+ value = ioread32(fotg210->reg + FOTG210_DMCR); -+ value |= DMCR_CHIP_EN; -+ iowrite32(value, fotg210->reg + FOTG210_DMCR); -+ - /* enable device global interrupt */ - value = ioread32(fotg210->reg + FOTG210_DMCR); - value |= DMCR_GLINT_EN; -@@ -1038,6 +1044,15 @@ static void fotg210_init(struct fotg210_ - iowrite32(GMIR_MHC_INT | GMIR_MOTG_INT | GMIR_INT_POLARITY, - fotg210->reg + FOTG210_GMIR); - -+ /* mask interrupts for groups other than 0-2 */ -+ iowrite32(~(DMIGR_MINT_G0 | DMIGR_MINT_G1 | DMIGR_MINT_G2), -+ fotg210->reg + FOTG210_DMIGR); -+ -+ /* udc software reset */ -+ iowrite32(DMCR_SFRST, fotg210->reg + FOTG210_DMCR); -+ /* Better wait a bit, but without a datasheet, no idea how long. */ -+ usleep_range(100, 200); -+ - /* disable device global interrupt */ - value = ioread32(fotg210->reg + FOTG210_DMCR); - value &= ~DMCR_GLINT_EN; ---- a/drivers/usb/fotg210/fotg210-udc.h -+++ b/drivers/usb/fotg210/fotg210-udc.h -@@ -58,6 +58,8 @@ - - /* Device Mask of Interrupt Group Register (0x130) */ - #define FOTG210_DMIGR 0x130 -+#define DMIGR_MINT_G2 (1 << 2) -+#define DMIGR_MINT_G1 (1 << 1) - #define DMIGR_MINT_G0 (1 << 0) - - /* Device Mask of Interrupt Source Group 0(0x134) */ diff --git a/target/linux/gemini/patches-6.1/0024-usb-fotg210-hcd-use-sysfs_emit-to-instead-of-scnprin.patch b/target/linux/gemini/patches-6.1/0024-usb-fotg210-hcd-use-sysfs_emit-to-instead-of-scnprin.patch deleted file mode 100644 index 680836110a0..00000000000 --- a/target/linux/gemini/patches-6.1/0024-usb-fotg210-hcd-use-sysfs_emit-to-instead-of-scnprin.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 482830a70408a5d30af264b3d6706f818c78b2b2 Mon Sep 17 00:00:00 2001 -From: Andy Shevchenko -Date: Fri, 20 Jan 2023 17:44:33 +0200 -Subject: [PATCH 24/29] usb: fotg210-hcd: use sysfs_emit() to instead of - scnprintf() - -Follow the advice of the Documentation/filesystems/sysfs.rst and show() -should only use sysfs_emit() or sysfs_emit_at() when formatting the -value to be returned to user space. - -Signed-off-by: Andy Shevchenko -Link: https://lore.kernel.org/r/20230120154437.22025-1-andriy.shevchenko@linux.intel.com -Signed-off-by: Greg Kroah-Hartman ---- ---- a/drivers/usb/fotg210/fotg210-hcd.c -+++ b/drivers/usb/fotg210/fotg210-hcd.c -@@ -4686,14 +4686,11 @@ static ssize_t uframe_periodic_max_show( - struct device_attribute *attr, char *buf) - { - struct fotg210_hcd *fotg210; -- int n; - - fotg210 = hcd_to_fotg210(bus_to_hcd(dev_get_drvdata(dev))); -- n = scnprintf(buf, PAGE_SIZE, "%d\n", fotg210->uframe_periodic_max); -- return n; -+ return sysfs_emit(buf, "%d\n", fotg210->uframe_periodic_max); - } - -- - static ssize_t uframe_periodic_max_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) - { diff --git a/target/linux/gemini/patches-6.1/0025-ARM-dts-gemini-Push-down-flash-address-size-cells.patch b/target/linux/gemini/patches-6.1/0025-ARM-dts-gemini-Push-down-flash-address-size-cells.patch deleted file mode 100644 index 1e031f1d4ff..00000000000 --- a/target/linux/gemini/patches-6.1/0025-ARM-dts-gemini-Push-down-flash-address-size-cells.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 6b84aa39a063eec883d410a9893cec70fce56163 Mon Sep 17 00:00:00 2001 -From: Linus Walleij -Date: Sun, 4 Dec 2022 20:02:28 +0100 -Subject: [PATCH 25/29] ARM: dts: gemini: Push down flash address/size cells - -The platforms not defining any OF partions complain like -this: - -../arch/arm/boot/dts/gemini.dtsi:19.25-28.5: Warning - (avoid_unnecessary_addr_size): /soc/flash@30000000: unnecessary - #address-cells/#size-cells without "ranges" or child "reg" property - -Get rid of this by only defining the address-cells and -size-cells where it is actually used by OF partitions. - -Link: https://lore.kernel.org/r/20221204190230.3345590-1-linus.walleij@linaro.org -Signed-off-by: Linus Walleij ---- ---- a/arch/arm/boot/dts/gemini-dlink-dns-313.dts -+++ b/arch/arm/boot/dts/gemini-dlink-dns-313.dts -@@ -164,6 +164,8 @@ - compatible = "cortina,gemini-flash", "jedec-flash"; - status = "okay"; - reg = <0x30000000 0x00080000>; -+ #address-cells = <1>; -+ #size-cells = <1>; - - /* - * This "RedBoot" is the Storlink derivative. ---- a/arch/arm/boot/dts/gemini-wbd111.dts -+++ b/arch/arm/boot/dts/gemini-wbd111.dts -@@ -86,6 +86,8 @@ - status = "okay"; - /* 8MB of flash */ - reg = <0x30000000 0x00800000>; -+ #address-cells = <1>; -+ #size-cells = <1>; - - partition@0 { - label = "RedBoot"; ---- a/arch/arm/boot/dts/gemini-wbd222.dts -+++ b/arch/arm/boot/dts/gemini-wbd222.dts -@@ -90,6 +90,8 @@ - status = "okay"; - /* 8MB of flash */ - reg = <0x30000000 0x00800000>; -+ #address-cells = <1>; -+ #size-cells = <1>; - - partition@0 { - label = "RedBoot"; ---- a/arch/arm/boot/dts/gemini.dtsi -+++ b/arch/arm/boot/dts/gemini.dtsi -@@ -22,8 +22,6 @@ - pinctrl-names = "default"; - pinctrl-0 = <&pflash_default_pins>; - bank-width = <2>; -- #address-cells = <1>; -- #size-cells = <1>; - status = "disabled"; - }; - diff --git a/target/linux/gemini/patches-6.1/0026-ARM-dts-gemini-wbd111-Use-RedBoot-partion-parser.patch b/target/linux/gemini/patches-6.1/0026-ARM-dts-gemini-wbd111-Use-RedBoot-partion-parser.patch deleted file mode 100644 index 1aff23ed1ba..00000000000 --- a/target/linux/gemini/patches-6.1/0026-ARM-dts-gemini-wbd111-Use-RedBoot-partion-parser.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 0e733f5af628210f372585e431504a7024e7b571 Mon Sep 17 00:00:00 2001 -From: Linus Walleij -Date: Sun, 4 Dec 2022 20:02:29 +0100 -Subject: [PATCH 26/29] ARM: dts: gemini: wbd111: Use RedBoot partion parser - -This is clearly a RedBoot partitioned device with 0x20000 -sized erase blocks. - -Link: https://lore.kernel.org/r/20221204190230.3345590-2-linus.walleij@linaro.org -Signed-off-by: Linus Walleij ---- ---- a/arch/arm/boot/dts/gemini-wbd111.dts -+++ b/arch/arm/boot/dts/gemini-wbd111.dts -@@ -86,36 +86,11 @@ - status = "okay"; - /* 8MB of flash */ - reg = <0x30000000 0x00800000>; -- #address-cells = <1>; -- #size-cells = <1>; - -- partition@0 { -- label = "RedBoot"; -- reg = <0x00000000 0x00020000>; -- read-only; -- }; -- partition@20000 { -- label = "kernel"; -- reg = <0x00020000 0x00100000>; -- }; -- partition@120000 { -- label = "rootfs"; -- reg = <0x00120000 0x006a0000>; -- }; -- partition@7c0000 { -- label = "VCTL"; -- reg = <0x007c0000 0x00010000>; -- read-only; -- }; -- partition@7d0000 { -- label = "cfg"; -- reg = <0x007d0000 0x00010000>; -- read-only; -- }; -- partition@7e0000 { -- label = "FIS"; -- reg = <0x007e0000 0x00010000>; -- read-only; -+ partitions { -+ compatible = "redboot-fis"; -+ /* Eraseblock at 0x7e0000 */ -+ fis-index-block = <0x3f>; - }; - }; - diff --git a/target/linux/gemini/patches-6.1/0027-ARM-dts-gemini-wbd222-Use-RedBoot-partion-parser.patch b/target/linux/gemini/patches-6.1/0027-ARM-dts-gemini-wbd222-Use-RedBoot-partion-parser.patch deleted file mode 100644 index 8cafeaa0dfe..00000000000 --- a/target/linux/gemini/patches-6.1/0027-ARM-dts-gemini-wbd222-Use-RedBoot-partion-parser.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 8558e2e1110a5daa4ac9e1c5b5c15e1651a8fb94 Mon Sep 17 00:00:00 2001 -From: Linus Walleij -Date: Sun, 4 Dec 2022 20:02:30 +0100 -Subject: [PATCH 27/29] ARM: dts: gemini: wbd222: Use RedBoot partion parser - -This is clearly a RedBoot partitioned device with 0x20000 -sized erase blocks. - -Link: https://lore.kernel.org/r/20221204190230.3345590-3-linus.walleij@linaro.org -Signed-off-by: Linus Walleij ---- ---- a/arch/arm/boot/dts/gemini-wbd222.dts -+++ b/arch/arm/boot/dts/gemini-wbd222.dts -@@ -90,36 +90,11 @@ - status = "okay"; - /* 8MB of flash */ - reg = <0x30000000 0x00800000>; -- #address-cells = <1>; -- #size-cells = <1>; - -- partition@0 { -- label = "RedBoot"; -- reg = <0x00000000 0x00020000>; -- read-only; -- }; -- partition@20000 { -- label = "kernel"; -- reg = <0x00020000 0x00100000>; -- }; -- partition@120000 { -- label = "rootfs"; -- reg = <0x00120000 0x006a0000>; -- }; -- partition@7c0000 { -- label = "VCTL"; -- reg = <0x007c0000 0x00010000>; -- read-only; -- }; -- partition@7d0000 { -- label = "cfg"; -- reg = <0x007d0000 0x00010000>; -- read-only; -- }; -- partition@7e0000 { -- label = "FIS"; -- reg = <0x007e0000 0x00010000>; -- read-only; -+ partitions { -+ compatible = "redboot-fis"; -+ /* Eraseblock at 0x7e0000 */ -+ fis-index-block = <0x3f>; - }; - }; - diff --git a/target/linux/gemini/patches-6.1/0028-ARM-dts-gemini-Fix-USB-block-version.patch b/target/linux/gemini/patches-6.1/0028-ARM-dts-gemini-Fix-USB-block-version.patch deleted file mode 100644 index fb93b70a313..00000000000 --- a/target/linux/gemini/patches-6.1/0028-ARM-dts-gemini-Fix-USB-block-version.patch +++ /dev/null @@ -1,31 +0,0 @@ -From d5c01ce4a1016507c69682894cf6b66301abca3d Mon Sep 17 00:00:00 2001 -From: Linus Walleij -Date: Mon, 23 Jan 2023 08:39:15 +0100 -Subject: [PATCH 28/29] ARM: dts: gemini: Fix USB block version - -The FOTG version in the Gemini is the FOTG200, fix this -up. - -Signed-off-by: Linus Walleij -Link: https://lore.kernel.org/r/20230123073916.2350839-1-linus.walleij@linaro.org ---- ---- a/arch/arm/boot/dts/gemini.dtsi -+++ b/arch/arm/boot/dts/gemini.dtsi -@@ -439,7 +439,7 @@ - }; - - usb0: usb@68000000 { -- compatible = "cortina,gemini-usb", "faraday,fotg210"; -+ compatible = "cortina,gemini-usb", "faraday,fotg200"; - reg = <0x68000000 0x1000>; - interrupts = <10 IRQ_TYPE_LEVEL_HIGH>; - resets = <&syscon GEMINI_RESET_USB0>; -@@ -460,7 +460,7 @@ - }; - - usb1: usb@69000000 { -- compatible = "cortina,gemini-usb", "faraday,fotg210"; -+ compatible = "cortina,gemini-usb", "faraday,fotg200"; - reg = <0x69000000 0x1000>; - interrupts = <11 IRQ_TYPE_LEVEL_HIGH>; - resets = <&syscon GEMINI_RESET_USB1>; diff --git a/target/linux/gemini/patches-6.1/0029-ARM-dts-gemini-Enable-DNS313-FOTG210-as-periph.patch b/target/linux/gemini/patches-6.1/0029-ARM-dts-gemini-Enable-DNS313-FOTG210-as-periph.patch deleted file mode 100644 index 667878170b7..00000000000 --- a/target/linux/gemini/patches-6.1/0029-ARM-dts-gemini-Enable-DNS313-FOTG210-as-periph.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 296184694ae7a4e388603c95499e98d30b21cc09 Mon Sep 17 00:00:00 2001 -From: Linus Walleij -Date: Mon, 23 Jan 2023 08:39:16 +0100 -Subject: [PATCH 29/29] ARM: dts: gemini: Enable DNS313 FOTG210 as periph - -Add the GPIO-based VBUS phy, and enable the FOTG210 -USB1 block for use as peripheral. - -Signed-off-by: Linus Walleij -Link: https://lore.kernel.org/r/20230123073916.2350839-2-linus.walleij@linaro.org ---- ---- a/arch/arm/boot/dts/gemini-dlink-dns-313.dts -+++ b/arch/arm/boot/dts/gemini-dlink-dns-313.dts -@@ -80,6 +80,15 @@ - #cooling-cells = <2>; - }; - -+ /* -+ * This is the type B USB connector on the device, -+ * a GPIO-controlled USB VBUS detect -+ */ -+ usb1_phy: phy { -+ compatible = "gpio-usb-b-connector", "usb-b-connector"; -+ #phy-cells = <0>; -+ vbus-gpios = <&gpio0 18 GPIO_ACTIVE_LOW>; -+ }; - - /* Global Mixed-Mode Technology G751 mounted on GPIO I2C */ - i2c { -@@ -302,5 +311,13 @@ - ide@63000000 { - status = "okay"; - }; -+ -+ usb@69000000 { -+ status = "okay"; -+ dr_mode = "peripheral"; -+ usb-phy = <&usb1_phy>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&usb_default_pins>; -+ }; - }; - }; ---- a/arch/arm/boot/dts/gemini.dtsi -+++ b/arch/arm/boot/dts/gemini.dtsi -@@ -455,6 +455,8 @@ - */ - pinctrl-names = "default"; - pinctrl-0 = <&usb_default_pins>; -+ /* Default to host mode */ -+ dr_mode = "host"; - syscon = <&syscon>; - status = "disabled"; - }; diff --git a/target/linux/gemini/patches-6.6/0001-net-ethernet-cortina-Drop-TSO-support.patch b/target/linux/gemini/patches-6.6/0001-net-ethernet-cortina-Drop-TSO-support.patch new file mode 100644 index 00000000000..43e0cb283aa --- /dev/null +++ b/target/linux/gemini/patches-6.6/0001-net-ethernet-cortina-Drop-TSO-support.patch @@ -0,0 +1,78 @@ +From f8001196455311eb128fcafd98cb2050a70218df Mon Sep 17 00:00:00 2001 +From: Linus Walleij +Date: Sat, 6 Jan 2024 01:12:22 +0100 +Subject: [PATCH 4/4] net: ethernet: cortina: Drop TSO support + +The recent change to allow large frames without hardware checksumming +slotted in software checksumming in the driver if hardware could not +do it. + +This will however upset TSO (TCP Segment Offloading). Typical +error dumps includes this: + +skb len=2961 headroom=222 headlen=66 tailroom=0 +(...) +WARNING: CPU: 0 PID: 956 at net/core/dev.c:3259 skb_warn_bad_offload+0x7c/0x108 +gemini-ethernet-port: caps=(0x0000010000154813, 0x00002007ffdd7889) + +And the packets do not go through. + +The TSO implementation is bogus: a TSO enabled driver must propagate +the skb_shinfo(skb)->gso_size value to the TSO engine on the NIC. + +Drop the size check and TSO offloading features for now: this +needs to be fixed up properly. + +After this ethernet works fine on Gemini devices with a direct connected +PHY such as D-Link DNS-313. + +Also tested to still be working with a DSA switch using the Gemini +ethernet as conduit interface. + +Link: https://lore.kernel.org/netdev/CANn89iJLfxng1sYL5Zk0mknXpyYQPCp83m3KgD2KJ2_hKCpEUg@mail.gmail.com/ +Suggested-by: Eric Dumazet +Fixes: d4d0c5b4d279 ("net: ethernet: cortina: Handle large frames") +Signed-off-by: Linus Walleij +Reviewed-by: Eric Dumazet +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/cortina/gemini.c | 15 ++------------- + 1 file changed, 2 insertions(+), 13 deletions(-) + +--- a/drivers/net/ethernet/cortina/gemini.c ++++ b/drivers/net/ethernet/cortina/gemini.c +@@ -79,8 +79,7 @@ MODULE_PARM_DESC(debug, "Debug level (0= + #define GMAC0_IRQ4_8 (GMAC0_MIB_INT_BIT | GMAC0_RX_OVERRUN_INT_BIT) + + #define GMAC_OFFLOAD_FEATURES (NETIF_F_SG | NETIF_F_IP_CSUM | \ +- NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM | \ +- NETIF_F_TSO | NETIF_F_TSO_ECN | NETIF_F_TSO6) ++ NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM) + + /** + * struct gmac_queue_page - page buffer per-page info +@@ -1143,23 +1142,13 @@ static int gmac_map_tx_bufs(struct net_d + struct gmac_txdesc *txd; + skb_frag_t *skb_frag; + dma_addr_t mapping; +- unsigned short mtu; + void *buffer; + int ret; + +- mtu = ETH_HLEN; +- mtu += netdev->mtu; +- if (skb->protocol == htons(ETH_P_8021Q)) +- mtu += VLAN_HLEN; +- ++ /* TODO: implement proper TSO using MTU in word3 */ + word1 = skb->len; + word3 = SOF_BIT; + +- if (word1 > mtu) { +- word1 |= TSS_MTU_ENABLE_BIT; +- word3 |= mtu; +- } +- + if (skb->len >= ETH_FRAME_LEN) { + /* Hardware offloaded checksumming isn't working on frames + * bigger than 1514 bytes. A hypothesis about this is that the diff --git a/target/linux/gemini/patches-6.6/0002-ARM-dts-gemini-Map-reset-keys-to-KEY_RESTART.patch b/target/linux/gemini/patches-6.6/0002-ARM-dts-gemini-Map-reset-keys-to-KEY_RESTART.patch new file mode 100644 index 00000000000..1d1ee2b46c7 --- /dev/null +++ b/target/linux/gemini/patches-6.6/0002-ARM-dts-gemini-Map-reset-keys-to-KEY_RESTART.patch @@ -0,0 +1,103 @@ +From 091cde88b5ff2a2ca5739ce41f9cf5640a95222f Mon Sep 17 00:00:00 2001 +From: Linus Walleij +Date: Sun, 11 Feb 2024 22:24:25 +0100 +Subject: [PATCH] ARM: dts: gemini: Map reset keys to KEY_RESTART + +This maps the misc "reset", "setup" and "facory reset" keys to the +only key a standard userspace is likely to understand: KEY_RESTART. +On OpenWrt this will simply restart the system under controlled +forms. + +Signed-off-by: Linus Walleij +Link: https://lore.kernel.org/r/20240211-gemini-dts-v1-3-6c09adeb4c2e@linaro.org +--- + arch/arm/boot/dts/gemini/gemini-dlink-dir-685.dts | 4 ++-- + arch/arm/boot/dts/gemini/gemini-dlink-dns-313.dts | 4 ++-- + arch/arm/boot/dts/gemini/gemini-sl93512r.dts | 2 +- + arch/arm/boot/dts/gemini/gemini-sq201.dts | 2 +- + arch/arm/boot/dts/gemini/gemini-wbd111.dts | 4 ++-- + arch/arm/boot/dts/gemini/gemini-wbd222.dts | 4 ++-- + 6 files changed, 10 insertions(+), 10 deletions(-) + +--- a/arch/arm/boot/dts/gemini/gemini-dlink-dir-685.dts ++++ b/arch/arm/boot/dts/gemini/gemini-dlink-dir-685.dts +@@ -27,10 +27,10 @@ + gpio_keys { + compatible = "gpio-keys"; + +- button-esc { ++ button-reset { + debounce-interval = <100>; + wakeup-source; +- linux,code = ; ++ linux,code = ; + label = "reset"; + /* Collides with LPC_LAD[0], UART DCD, SSP 97RST */ + gpios = <&gpio0 8 GPIO_ACTIVE_LOW>; +--- a/arch/arm/boot/dts/gemini/gemini-dlink-dns-313.dts ++++ b/arch/arm/boot/dts/gemini/gemini-dlink-dns-313.dts +@@ -33,10 +33,10 @@ + gpio_keys { + compatible = "gpio-keys"; + +- button-esc { ++ button-reset { + debounce-interval = <100>; + wakeup-source; +- linux,code = ; ++ linux,code = ; + label = "reset"; + gpios = <&gpio1 31 GPIO_ACTIVE_LOW>; + }; +--- a/arch/arm/boot/dts/gemini/gemini-sl93512r.dts ++++ b/arch/arm/boot/dts/gemini/gemini-sl93512r.dts +@@ -43,7 +43,7 @@ + button-setup { + debounce-interval = <50>; + wakeup-source; +- linux,code = ; ++ linux,code = ; + label = "factory reset"; + /* Conflict with NAND flash */ + gpios = <&gpio0 18 GPIO_ACTIVE_LOW>; +--- a/arch/arm/boot/dts/gemini/gemini-sq201.dts ++++ b/arch/arm/boot/dts/gemini/gemini-sq201.dts +@@ -30,7 +30,7 @@ + button-setup { + debounce-interval = <100>; + wakeup-source; +- linux,code = ; ++ linux,code = ; + label = "factory reset"; + /* Conflict with NAND flash */ + gpios = <&gpio0 18 GPIO_ACTIVE_LOW>; +--- a/arch/arm/boot/dts/gemini/gemini-wbd111.dts ++++ b/arch/arm/boot/dts/gemini/gemini-wbd111.dts +@@ -28,10 +28,10 @@ + gpio_keys { + compatible = "gpio-keys"; + +- button-setup { ++ button-reset { + debounce-interval = <100>; + wakeup-source; +- linux,code = ; ++ linux,code = ; + label = "reset"; + /* Conflict with ICE */ + gpios = <&gpio0 5 GPIO_ACTIVE_LOW>; +--- a/arch/arm/boot/dts/gemini/gemini-wbd222.dts ++++ b/arch/arm/boot/dts/gemini/gemini-wbd222.dts +@@ -27,10 +27,10 @@ + gpio_keys { + compatible = "gpio-keys"; + +- button-setup { ++ button-reset { + debounce-interval = <100>; + wakeup-source; +- linux,code = ; ++ linux,code = ; + label = "reset"; + /* Conflict with ICE */ + gpios = <&gpio0 5 GPIO_ACTIVE_LOW>; diff --git a/target/linux/gemini/patches-6.1/300-ARM-dts-Augment-DIR-685-partition-table-for-OpenWrt.patch b/target/linux/gemini/patches-6.6/300-ARM-dts-Augment-DIR-685-partition-table-for-OpenWrt.patch similarity index 70% rename from target/linux/gemini/patches-6.1/300-ARM-dts-Augment-DIR-685-partition-table-for-OpenWrt.patch rename to target/linux/gemini/patches-6.6/300-ARM-dts-Augment-DIR-685-partition-table-for-OpenWrt.patch index 99e0d2731da..613c3a842f1 100644 --- a/target/linux/gemini/patches-6.1/300-ARM-dts-Augment-DIR-685-partition-table-for-OpenWrt.patch +++ b/target/linux/gemini/patches-6.6/300-ARM-dts-Augment-DIR-685-partition-table-for-OpenWrt.patch @@ -1,7 +1,7 @@ -From 36ee838bf83c01cff7cb47c7b07be278d2950ac0 Mon Sep 17 00:00:00 2001 +From c1aa34cd568bc7b86b82353034070c32b6ebe6db Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 11 Mar 2019 15:44:29 +0100 -Subject: [PATCH 2/2] ARM: dts: Augment DIR-685 partition table for OpenWrt +Subject: [PATCH] ARM: dts: Augment DIR-685 partition table for OpenWrt Rename the firmware partition so that the firmware MTD splitter will do its job, drop the rootfs arguments as @@ -9,8 +9,11 @@ the MTD splitter will set this up automatically. Signed-off-by: Linus Walleij --- ---- a/arch/arm/boot/dts/gemini-dlink-dir-685.dts -+++ b/arch/arm/boot/dts/gemini-dlink-dir-685.dts + arch/arm/boot/dts/gemini/gemini-dlink-dir-685.dts | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/arch/arm/boot/dts/gemini/gemini-dlink-dir-685.dts ++++ b/arch/arm/boot/dts/gemini/gemini-dlink-dir-685.dts @@ -20,7 +20,7 @@ };