ipq40xx: drop kernel 4.14 support
kernel 4.14 is no longer supported with existing DTS files. Fixes: #214 Signed-off-by: CN_SZTL <cnsztl@project-openwrt.eu.org>
This commit is contained in:
parent
763a91567c
commit
d7c06b9040
@ -1,504 +0,0 @@
|
||||
CONFIG_ALIGNMENT_TRAP=y
|
||||
# CONFIG_APQ_GCC_8084 is not set
|
||||
# CONFIG_APQ_MMCC_8084 is not set
|
||||
CONFIG_AR40XX_PHY=y
|
||||
CONFIG_ARCH_CLOCKSOURCE_DATA=y
|
||||
CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y
|
||||
CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
|
||||
CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y
|
||||
CONFIG_ARCH_HAS_SET_MEMORY=y
|
||||
CONFIG_ARCH_HAS_SG_CHAIN=y
|
||||
CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y
|
||||
CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y
|
||||
CONFIG_ARCH_HAS_TICK_BROADCAST=y
|
||||
CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
|
||||
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
|
||||
CONFIG_ARCH_IPQ40XX=y
|
||||
# CONFIG_ARCH_MDM9615 is not set
|
||||
CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
|
||||
# CONFIG_ARCH_MSM8960 is not set
|
||||
# CONFIG_ARCH_MSM8974 is not set
|
||||
# CONFIG_ARCH_MSM8X60 is not set
|
||||
CONFIG_ARCH_MULTIPLATFORM=y
|
||||
# CONFIG_ARCH_MULTI_CPU_AUTO is not set
|
||||
CONFIG_ARCH_MULTI_V6_V7=y
|
||||
CONFIG_ARCH_MULTI_V7=y
|
||||
CONFIG_ARCH_NR_GPIO=0
|
||||
CONFIG_ARCH_OPTIONAL_KERNEL_RWX=y
|
||||
CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT=y
|
||||
CONFIG_ARCH_QCOM=y
|
||||
# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
|
||||
# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
|
||||
CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y
|
||||
CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y
|
||||
CONFIG_ARCH_SUPPORTS_UPROBES=y
|
||||
CONFIG_ARCH_SUSPEND_POSSIBLE=y
|
||||
CONFIG_ARCH_USE_BUILTIN_BSWAP=y
|
||||
CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
|
||||
CONFIG_ARCH_WANT_GENERAL_HUGETLB=y
|
||||
CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
|
||||
CONFIG_ARM=y
|
||||
CONFIG_ARM_AMBA=y
|
||||
CONFIG_ARM_APPENDED_DTB=y
|
||||
CONFIG_ARM_ARCH_TIMER=y
|
||||
CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
|
||||
# CONFIG_ARM_ATAG_DTB_COMPAT is not set
|
||||
CONFIG_ARM_CPUIDLE=y
|
||||
CONFIG_ARM_CPU_SUSPEND=y
|
||||
# CONFIG_ARM_CPU_TOPOLOGY is not set
|
||||
CONFIG_ARM_CRYPTO=y
|
||||
CONFIG_ARM_GIC=y
|
||||
CONFIG_ARM_HAS_SG_CHAIN=y
|
||||
CONFIG_ARM_L1_CACHE_SHIFT=6
|
||||
CONFIG_ARM_L1_CACHE_SHIFT_6=y
|
||||
# CONFIG_ARM_LPAE is not set
|
||||
CONFIG_ARM_PATCH_IDIV=y
|
||||
CONFIG_ARM_PATCH_PHYS_VIRT=y
|
||||
# CONFIG_ARM_SMMU is not set
|
||||
# CONFIG_ARM_SP805_WATCHDOG is not set
|
||||
CONFIG_ARM_THUMB=y
|
||||
# CONFIG_ARM_THUMBEE is not set
|
||||
CONFIG_ARM_UNWIND=y
|
||||
CONFIG_ARM_VIRT_EXT=y
|
||||
CONFIG_AT803X_PHY=y
|
||||
CONFIG_AUTO_ZRELADDR=y
|
||||
CONFIG_BLK_DEV_LOOP=y
|
||||
CONFIG_BLK_MQ_PCI=y
|
||||
CONFIG_BOUNCE=y
|
||||
# CONFIG_CACHE_L2X0 is not set
|
||||
CONFIG_CC_HAS_ASM_GOTO=y
|
||||
CONFIG_CLKDEV_LOOKUP=y
|
||||
CONFIG_CLKSRC_QCOM=y
|
||||
CONFIG_CLONE_BACKWARDS=y
|
||||
CONFIG_COMMON_CLK=y
|
||||
CONFIG_COMMON_CLK_QCOM=y
|
||||
CONFIG_CPUFREQ_DT=y
|
||||
CONFIG_CPUFREQ_DT_PLATDEV=y
|
||||
CONFIG_CPU_32v6K=y
|
||||
CONFIG_CPU_32v7=y
|
||||
CONFIG_CPU_ABRT_EV7=y
|
||||
# CONFIG_CPU_BIG_ENDIAN is not set
|
||||
# CONFIG_CPU_BPREDICT_DISABLE is not set
|
||||
CONFIG_CPU_CACHE_V7=y
|
||||
CONFIG_CPU_CACHE_VIPT=y
|
||||
CONFIG_CPU_COPY_V6=y
|
||||
CONFIG_CPU_CP15=y
|
||||
CONFIG_CPU_CP15_MMU=y
|
||||
CONFIG_CPU_FREQ=y
|
||||
CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
|
||||
# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
|
||||
CONFIG_CPU_FREQ_GOV_ATTR_SET=y
|
||||
CONFIG_CPU_FREQ_GOV_COMMON=y
|
||||
# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
|
||||
CONFIG_CPU_FREQ_GOV_ONDEMAND=y
|
||||
CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
|
||||
# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
|
||||
# CONFIG_CPU_FREQ_GOV_USERSPACE is not set
|
||||
CONFIG_CPU_FREQ_STAT=y
|
||||
CONFIG_CPU_HAS_ASID=y
|
||||
# CONFIG_CPU_ICACHE_DISABLE is not set
|
||||
CONFIG_CPU_IDLE=y
|
||||
CONFIG_CPU_IDLE_GOV_LADDER=y
|
||||
CONFIG_CPU_IDLE_GOV_MENU=y
|
||||
CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y
|
||||
CONFIG_CPU_PABRT_V7=y
|
||||
CONFIG_CPU_PM=y
|
||||
CONFIG_CPU_RMAP=y
|
||||
CONFIG_CPU_SPECTRE=y
|
||||
CONFIG_CPU_THERMAL=y
|
||||
CONFIG_CPU_THUMB_CAPABLE=y
|
||||
CONFIG_CPU_TLB_V7=y
|
||||
CONFIG_CPU_V7=y
|
||||
CONFIG_CRC16=y
|
||||
# CONFIG_CRC32_SARWATE is not set
|
||||
CONFIG_CRC32_SLICEBY8=y
|
||||
CONFIG_CRYPTO_ACOMP2=y
|
||||
CONFIG_CRYPTO_AEAD=y
|
||||
CONFIG_CRYPTO_AEAD2=y
|
||||
CONFIG_CRYPTO_AES_ARM=y
|
||||
CONFIG_CRYPTO_AES_ARM_BS=y
|
||||
CONFIG_CRYPTO_CBC=y
|
||||
CONFIG_CRYPTO_CTR=y
|
||||
CONFIG_CRYPTO_DEFLATE=y
|
||||
CONFIG_CRYPTO_DES=y
|
||||
CONFIG_CRYPTO_DEV_QCE=y
|
||||
# CONFIG_CRYPTO_DEV_QCE_ENABLE_ALL is not set
|
||||
# CONFIG_CRYPTO_DEV_QCE_ENABLE_SHA is not set
|
||||
CONFIG_CRYPTO_DEV_QCE_ENABLE_SKCIPHER=y
|
||||
CONFIG_CRYPTO_DEV_QCE_SW_MAX_LEN=512
|
||||
CONFIG_CRYPTO_DEV_QCOM_RNG=y
|
||||
CONFIG_CRYPTO_DRBG=y
|
||||
CONFIG_CRYPTO_DRBG_HMAC=y
|
||||
CONFIG_CRYPTO_DRBG_MENU=y
|
||||
CONFIG_CRYPTO_ECB=y
|
||||
CONFIG_CRYPTO_GF128MUL=y
|
||||
# CONFIG_CRYPTO_GHASH_ARM_CE is not set
|
||||
CONFIG_CRYPTO_HASH=y
|
||||
CONFIG_CRYPTO_HASH2=y
|
||||
CONFIG_CRYPTO_HMAC=y
|
||||
CONFIG_CRYPTO_HW=y
|
||||
CONFIG_CRYPTO_JITTERENTROPY=y
|
||||
CONFIG_CRYPTO_LZO=y
|
||||
CONFIG_CRYPTO_MANAGER=y
|
||||
CONFIG_CRYPTO_MANAGER2=y
|
||||
CONFIG_CRYPTO_NULL=y
|
||||
CONFIG_CRYPTO_NULL2=y
|
||||
CONFIG_CRYPTO_RNG=y
|
||||
CONFIG_CRYPTO_RNG2=y
|
||||
CONFIG_CRYPTO_RNG_DEFAULT=y
|
||||
CONFIG_CRYPTO_SEQIV=y
|
||||
# CONFIG_CRYPTO_SHA1_ARM_CE is not set
|
||||
# CONFIG_CRYPTO_SHA1_ARM_NEON is not set
|
||||
CONFIG_CRYPTO_SHA256=y
|
||||
CONFIG_CRYPTO_SHA256_ARM=y
|
||||
CONFIG_CRYPTO_SIMD=y
|
||||
CONFIG_CRYPTO_WORKQUEUE=y
|
||||
CONFIG_CRYPTO_XTS=y
|
||||
CONFIG_DCACHE_WORD_ACCESS=y
|
||||
CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S"
|
||||
# CONFIG_DEBUG_UART_8250 is not set
|
||||
# CONFIG_DEBUG_USER is not set
|
||||
CONFIG_DMADEVICES=y
|
||||
CONFIG_DMA_ENGINE=y
|
||||
CONFIG_DMA_OF=y
|
||||
CONFIG_DMA_SHARED_BUFFER=y
|
||||
CONFIG_DMA_VIRTUAL_CHANNELS=y
|
||||
CONFIG_DTC=y
|
||||
CONFIG_DT_IDLE_STATES=y
|
||||
CONFIG_DYNAMIC_DEBUG=y
|
||||
CONFIG_EDAC_ATOMIC_SCRUB=y
|
||||
CONFIG_EDAC_SUPPORT=y
|
||||
CONFIG_EEPROM_AT24=y
|
||||
CONFIG_ESSEDMA=y
|
||||
CONFIG_EXTCON=y
|
||||
CONFIG_FIXED_PHY=y
|
||||
CONFIG_FIX_EARLYCON_MEM=y
|
||||
CONFIG_GENERIC_ALLOCATOR=y
|
||||
CONFIG_GENERIC_BUG=y
|
||||
CONFIG_GENERIC_CLOCKEVENTS=y
|
||||
CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
|
||||
CONFIG_GENERIC_CPU_AUTOPROBE=y
|
||||
CONFIG_GENERIC_EARLY_IOREMAP=y
|
||||
CONFIG_GENERIC_IDLE_POLL_SETUP=y
|
||||
CONFIG_GENERIC_IO=y
|
||||
CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y
|
||||
CONFIG_GENERIC_IRQ_SHOW=y
|
||||
CONFIG_GENERIC_IRQ_SHOW_LEVEL=y
|
||||
CONFIG_GENERIC_MSI_IRQ=y
|
||||
CONFIG_GENERIC_MSI_IRQ_DOMAIN=y
|
||||
CONFIG_GENERIC_PCI_IOMAP=y
|
||||
CONFIG_GENERIC_PHY=y
|
||||
CONFIG_GENERIC_PINCONF=y
|
||||
CONFIG_GENERIC_PINCTRL_GROUPS=y
|
||||
CONFIG_GENERIC_PINMUX_FUNCTIONS=y
|
||||
CONFIG_GENERIC_SCHED_CLOCK=y
|
||||
CONFIG_GENERIC_SMP_IDLE_THREAD=y
|
||||
CONFIG_GENERIC_STRNCPY_FROM_USER=y
|
||||
CONFIG_GENERIC_STRNLEN_USER=y
|
||||
CONFIG_GENERIC_TIME_VSYSCALL=y
|
||||
CONFIG_GPIOLIB=y
|
||||
CONFIG_GPIOLIB_IRQCHIP=y
|
||||
CONFIG_GPIO_74X164=y
|
||||
CONFIG_GPIO_SYSFS=y
|
||||
CONFIG_GPIO_WATCHDOG=y
|
||||
# CONFIG_GPIO_WATCHDOG_ARCH_INITCALL is not set
|
||||
# CONFIG_GRO_CELLS is not set
|
||||
CONFIG_HANDLE_DOMAIN_IRQ=y
|
||||
CONFIG_HARDEN_BRANCH_PREDICTOR=y
|
||||
CONFIG_HARDIRQS_SW_RESEND=y
|
||||
CONFIG_HAS_DMA=y
|
||||
CONFIG_HAS_IOMEM=y
|
||||
CONFIG_HAS_IOPORT_MAP=y
|
||||
# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
|
||||
CONFIG_HAVE_ARCH_AUDITSYSCALL=y
|
||||
CONFIG_HAVE_ARCH_BITREVERSE=y
|
||||
CONFIG_HAVE_ARCH_JUMP_LABEL=y
|
||||
CONFIG_HAVE_ARCH_KGDB=y
|
||||
CONFIG_HAVE_ARCH_PFN_VALID=y
|
||||
CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
|
||||
CONFIG_HAVE_ARCH_TRACEHOOK=y
|
||||
CONFIG_HAVE_ARM_ARCH_TIMER=y
|
||||
CONFIG_HAVE_ARM_SMCCC=y
|
||||
# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
|
||||
CONFIG_HAVE_CC_STACKPROTECTOR=y
|
||||
CONFIG_HAVE_CLK=y
|
||||
CONFIG_HAVE_CLK_PREPARE=y
|
||||
CONFIG_HAVE_CONTEXT_TRACKING=y
|
||||
CONFIG_HAVE_C_RECORDMCOUNT=y
|
||||
CONFIG_HAVE_DEBUG_KMEMLEAK=y
|
||||
CONFIG_HAVE_DMA_API_DEBUG=y
|
||||
CONFIG_HAVE_DMA_CONTIGUOUS=y
|
||||
CONFIG_HAVE_DYNAMIC_FTRACE=y
|
||||
CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y
|
||||
CONFIG_HAVE_EBPF_JIT=y
|
||||
CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
|
||||
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
|
||||
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
|
||||
CONFIG_HAVE_FUNCTION_TRACER=y
|
||||
CONFIG_HAVE_GENERIC_DMA_COHERENT=y
|
||||
CONFIG_HAVE_IDE=y
|
||||
CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
|
||||
CONFIG_HAVE_MEMBLOCK=y
|
||||
CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
|
||||
CONFIG_HAVE_NET_DSA=y
|
||||
CONFIG_HAVE_OPROFILE=y
|
||||
CONFIG_HAVE_OPTPROBES=y
|
||||
CONFIG_HAVE_PERF_EVENTS=y
|
||||
CONFIG_HAVE_PERF_REGS=y
|
||||
CONFIG_HAVE_PERF_USER_STACK_DUMP=y
|
||||
CONFIG_HAVE_PROC_CPU=y
|
||||
CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
|
||||
CONFIG_HAVE_SMP=y
|
||||
CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
|
||||
CONFIG_HAVE_UID16=y
|
||||
CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
|
||||
CONFIG_HIGHMEM=y
|
||||
# CONFIG_HIGHPTE is not set
|
||||
CONFIG_HWSPINLOCK=y
|
||||
CONFIG_HWSPINLOCK_QCOM=y
|
||||
CONFIG_HW_RANDOM=y
|
||||
CONFIG_HW_RANDOM_MSM=y
|
||||
CONFIG_HZ_FIXED=0
|
||||
CONFIG_I2C=y
|
||||
CONFIG_I2C_BOARDINFO=y
|
||||
CONFIG_I2C_CHARDEV=y
|
||||
CONFIG_I2C_HELPER_AUTO=y
|
||||
CONFIG_I2C_QUP=y
|
||||
CONFIG_INITRAMFS_SOURCE=""
|
||||
CONFIG_IOMMU_HELPER=y
|
||||
# CONFIG_IOMMU_IO_PGTABLE_ARMV7S is not set
|
||||
# CONFIG_IOMMU_IO_PGTABLE_LPAE is not set
|
||||
CONFIG_IOMMU_SUPPORT=y
|
||||
CONFIG_IPQ_GCC_4019=y
|
||||
# CONFIG_IPQ_GCC_806X is not set
|
||||
# CONFIG_IPQ_GCC_8074 is not set
|
||||
# CONFIG_IPQ_LCC_806X is not set
|
||||
CONFIG_IRQCHIP=y
|
||||
CONFIG_IRQ_DOMAIN=y
|
||||
CONFIG_IRQ_DOMAIN_HIERARCHY=y
|
||||
CONFIG_IRQ_FORCED_THREADING=y
|
||||
CONFIG_IRQ_WORK=y
|
||||
CONFIG_LEDS_LP5523=y
|
||||
CONFIG_LEDS_LP5562=y
|
||||
CONFIG_LEDS_LP55XX_COMMON=y
|
||||
CONFIG_LIBFDT=y
|
||||
CONFIG_LOCK_SPIN_ON_OWNER=y
|
||||
CONFIG_LZO_COMPRESS=y
|
||||
CONFIG_LZO_DECOMPRESS=y
|
||||
CONFIG_MDIO_BITBANG=y
|
||||
CONFIG_MDIO_BUS=y
|
||||
CONFIG_MDIO_DEVICE=y
|
||||
CONFIG_MDIO_GPIO=y
|
||||
CONFIG_MDIO_IPQ40XX=y
|
||||
# CONFIG_MDM_GCC_9615 is not set
|
||||
# CONFIG_MDM_LCC_9615 is not set
|
||||
# CONFIG_MFD_QCOM_RPM is not set
|
||||
# CONFIG_MFD_SPMI_PMIC is not set
|
||||
CONFIG_MFD_SYSCON=y
|
||||
CONFIG_MIGHT_HAVE_CACHE_L2X0=y
|
||||
CONFIG_MIGHT_HAVE_PCI=y
|
||||
CONFIG_MIGRATION=y
|
||||
CONFIG_MMC=y
|
||||
CONFIG_MMC_BLOCK=y
|
||||
CONFIG_MMC_SDHCI=y
|
||||
CONFIG_MMC_SDHCI_IO_ACCESSORS=y
|
||||
CONFIG_MMC_SDHCI_MSM=y
|
||||
# CONFIG_MMC_SDHCI_PCI is not set
|
||||
CONFIG_MMC_SDHCI_PLTFM=y
|
||||
# CONFIG_MMC_TIFM_SD is not set
|
||||
CONFIG_MODULES_USE_ELF_REL=y
|
||||
# CONFIG_MSM_GCC_8660 is not set
|
||||
# CONFIG_MSM_GCC_8916 is not set
|
||||
# CONFIG_MSM_GCC_8960 is not set
|
||||
# CONFIG_MSM_GCC_8974 is not set
|
||||
# CONFIG_MSM_GCC_8994 is not set
|
||||
# CONFIG_MSM_GCC_8996 is not set
|
||||
# CONFIG_MSM_LCC_8960 is not set
|
||||
# CONFIG_MSM_MMCC_8960 is not set
|
||||
# CONFIG_MSM_MMCC_8974 is not set
|
||||
# CONFIG_MSM_MMCC_8996 is not set
|
||||
CONFIG_MTD_CMDLINE_PARTS=y
|
||||
CONFIG_MTD_M25P80=y
|
||||
CONFIG_MTD_NAND=y
|
||||
CONFIG_MTD_NAND_ECC=y
|
||||
CONFIG_MTD_NAND_QCOM=y
|
||||
CONFIG_MTD_SPINAND_MT29F=y
|
||||
CONFIG_MTD_SPINAND_ONDIEECC=y
|
||||
CONFIG_MTD_SPI_NOR=y
|
||||
CONFIG_MTD_SPLIT_FIRMWARE=y
|
||||
CONFIG_MTD_SPLIT_FIT_FW=y
|
||||
CONFIG_MTD_UBI=y
|
||||
CONFIG_MTD_UBI_BEB_LIMIT=20
|
||||
CONFIG_MTD_UBI_BLOCK=y
|
||||
# CONFIG_MTD_UBI_FASTMAP is not set
|
||||
# CONFIG_MTD_UBI_GLUEBI is not set
|
||||
CONFIG_MTD_UBI_WL_THRESHOLD=4096
|
||||
CONFIG_MULTI_IRQ_HANDLER=y
|
||||
CONFIG_MUTEX_SPIN_ON_OWNER=y
|
||||
CONFIG_NEED_DMA_MAP_STATE=y
|
||||
CONFIG_NEON=y
|
||||
CONFIG_NET_FLOW_LIMIT=y
|
||||
CONFIG_NET_PTP_CLASSIFY=y
|
||||
CONFIG_NLS=y
|
||||
CONFIG_NO_BOOTMEM=y
|
||||
CONFIG_NO_HZ=y
|
||||
CONFIG_NO_HZ_COMMON=y
|
||||
CONFIG_NO_HZ_IDLE=y
|
||||
CONFIG_NR_CPUS=4
|
||||
CONFIG_NVMEM=y
|
||||
CONFIG_OF=y
|
||||
CONFIG_OF_ADDRESS=y
|
||||
CONFIG_OF_ADDRESS_PCI=y
|
||||
CONFIG_OF_EARLY_FLATTREE=y
|
||||
CONFIG_OF_FLATTREE=y
|
||||
CONFIG_OF_GPIO=y
|
||||
CONFIG_OF_IRQ=y
|
||||
CONFIG_OF_MDIO=y
|
||||
CONFIG_OF_NET=y
|
||||
CONFIG_OF_PCI=y
|
||||
CONFIG_OF_PCI_IRQ=y
|
||||
CONFIG_OF_RESERVED_MEM=y
|
||||
CONFIG_OLD_SIGACTION=y
|
||||
CONFIG_OLD_SIGSUSPEND3=y
|
||||
CONFIG_OPTEE=y
|
||||
CONFIG_PADATA=y
|
||||
CONFIG_PAGE_OFFSET=0xC0000000
|
||||
CONFIG_PCI=y
|
||||
CONFIG_PCIEAER=y
|
||||
CONFIG_PCIEPORTBUS=y
|
||||
CONFIG_PCIE_DW=y
|
||||
CONFIG_PCIE_DW_HOST=y
|
||||
CONFIG_PCIE_QCOM=y
|
||||
CONFIG_PCI_DISABLE_COMMON_QUIRKS=y
|
||||
CONFIG_PCI_DOMAINS=y
|
||||
CONFIG_PCI_DOMAINS_GENERIC=y
|
||||
CONFIG_PCI_MSI=y
|
||||
CONFIG_PCI_MSI_IRQ_DOMAIN=y
|
||||
CONFIG_PERF_USE_VMALLOC=y
|
||||
CONFIG_PGTABLE_LEVELS=2
|
||||
CONFIG_PHYLIB=y
|
||||
# CONFIG_PHY_QCOM_APQ8064_SATA is not set
|
||||
CONFIG_PHY_QCOM_IPQ4019_USB=y
|
||||
# CONFIG_PHY_QCOM_IPQ806X_SATA is not set
|
||||
# CONFIG_PHY_QCOM_QMP is not set
|
||||
# CONFIG_PHY_QCOM_QUSB2 is not set
|
||||
# CONFIG_PHY_QCOM_UFS is not set
|
||||
CONFIG_PINCTRL=y
|
||||
# CONFIG_PINCTRL_APQ8064 is not set
|
||||
# CONFIG_PINCTRL_APQ8084 is not set
|
||||
CONFIG_PINCTRL_IPQ4019=y
|
||||
# CONFIG_PINCTRL_IPQ8064 is not set
|
||||
# CONFIG_PINCTRL_IPQ8074 is not set
|
||||
# CONFIG_PINCTRL_MDM9615 is not set
|
||||
CONFIG_PINCTRL_MSM=y
|
||||
# CONFIG_PINCTRL_MSM8660 is not set
|
||||
# CONFIG_PINCTRL_MSM8916 is not set
|
||||
# CONFIG_PINCTRL_MSM8960 is not set
|
||||
# CONFIG_PINCTRL_MSM8994 is not set
|
||||
# CONFIG_PINCTRL_MSM8996 is not set
|
||||
# CONFIG_PINCTRL_QCOM_SPMI_PMIC is not set
|
||||
# CONFIG_PINCTRL_QCOM_SSBI_PMIC is not set
|
||||
CONFIG_PM_OPP=y
|
||||
CONFIG_POWER_RESET=y
|
||||
CONFIG_POWER_RESET_MSM=y
|
||||
CONFIG_POWER_SUPPLY=y
|
||||
CONFIG_PPS=y
|
||||
CONFIG_PRINTK_TIME=y
|
||||
CONFIG_PTP_1588_CLOCK=y
|
||||
CONFIG_QCOM_BAM_DMA=y
|
||||
# CONFIG_QCOM_EBI2 is not set
|
||||
# CONFIG_QCOM_GSBI is not set
|
||||
# CONFIG_QCOM_IOMMU is not set
|
||||
CONFIG_QCOM_PM=y
|
||||
CONFIG_QCOM_QFPROM=y
|
||||
CONFIG_QCOM_SCM=y
|
||||
CONFIG_QCOM_SCM_32=y
|
||||
CONFIG_QCOM_SMEM=y
|
||||
# CONFIG_QCOM_SMP2P is not set
|
||||
# CONFIG_QCOM_SMSM is not set
|
||||
CONFIG_QCOM_TCSR=y
|
||||
# CONFIG_QCOM_TSENS is not set
|
||||
CONFIG_QCOM_WDT=y
|
||||
# CONFIG_QRTR is not set
|
||||
CONFIG_RAS=y
|
||||
CONFIG_RATIONAL=y
|
||||
CONFIG_RCU_CPU_STALL_TIMEOUT=21
|
||||
CONFIG_RCU_NEED_SEGCBLIST=y
|
||||
CONFIG_RCU_STALL_COMMON=y
|
||||
CONFIG_REGMAP=y
|
||||
CONFIG_REGMAP_I2C=y
|
||||
CONFIG_REGMAP_MMIO=y
|
||||
CONFIG_REGMAP_SPI=y
|
||||
CONFIG_REGULATOR=y
|
||||
CONFIG_REGULATOR_FIXED_VOLTAGE=y
|
||||
# CONFIG_REGULATOR_QCOM_SPMI is not set
|
||||
CONFIG_REGULATOR_VCTRL=y
|
||||
CONFIG_REGULATOR_VQMMC_IPQ4019=y
|
||||
CONFIG_RESET_CONTROLLER=y
|
||||
CONFIG_RFS_ACCEL=y
|
||||
# CONFIG_RPMSG_QCOM_SMD is not set
|
||||
CONFIG_RPS=y
|
||||
CONFIG_RTC_CLASS=y
|
||||
# CONFIG_RTC_DRV_CMOS is not set
|
||||
CONFIG_RTC_I2C_AND_SPI=y
|
||||
CONFIG_RWSEM_SPIN_ON_OWNER=y
|
||||
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
|
||||
# CONFIG_SCHED_INFO is not set
|
||||
# CONFIG_SCSI_DMA is not set
|
||||
CONFIG_SERIAL_8250_FSL=y
|
||||
# CONFIG_SERIAL_AMBA_PL011 is not set
|
||||
CONFIG_SERIAL_MSM=y
|
||||
CONFIG_SERIAL_MSM_CONSOLE=y
|
||||
CONFIG_SMP=y
|
||||
CONFIG_SMP_ON_UP=y
|
||||
CONFIG_SPARSE_IRQ=y
|
||||
CONFIG_SPI=y
|
||||
CONFIG_SPI_BITBANG=y
|
||||
CONFIG_SPI_GPIO=y
|
||||
CONFIG_SPI_MASTER=y
|
||||
CONFIG_SPI_QUP=y
|
||||
CONFIG_SPMI=y
|
||||
CONFIG_SPMI_MSM_PMIC_ARB=y
|
||||
CONFIG_SRCU=y
|
||||
CONFIG_SWCONFIG=y
|
||||
CONFIG_SWCONFIG_LEDS=y
|
||||
CONFIG_SWIOTLB=y
|
||||
CONFIG_SWPHY=y
|
||||
CONFIG_SWP_EMULATE=y
|
||||
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
|
||||
CONFIG_TEE=y
|
||||
CONFIG_THERMAL=y
|
||||
CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
|
||||
CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0
|
||||
CONFIG_THERMAL_GOV_STEP_WISE=y
|
||||
CONFIG_THERMAL_OF=y
|
||||
# CONFIG_THUMB2_KERNEL is not set
|
||||
CONFIG_TICK_CPU_ACCOUNTING=y
|
||||
CONFIG_TIMER_OF=y
|
||||
CONFIG_TIMER_PROBE=y
|
||||
CONFIG_TREE_RCU=y
|
||||
CONFIG_TREE_SRCU=y
|
||||
CONFIG_UBIFS_FS=y
|
||||
CONFIG_UBIFS_FS_ADVANCED_COMPR=y
|
||||
CONFIG_UBIFS_FS_LZO=y
|
||||
CONFIG_UBIFS_FS_ZLIB=y
|
||||
CONFIG_UEVENT_HELPER_PATH=""
|
||||
CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
|
||||
CONFIG_USB=y
|
||||
CONFIG_USB_COMMON=y
|
||||
# CONFIG_USB_EHCI_HCD is not set
|
||||
# CONFIG_USB_QCOM_8X16_PHY is not set
|
||||
CONFIG_USB_SUPPORT=y
|
||||
CONFIG_USE_OF=y
|
||||
CONFIG_VDSO=y
|
||||
CONFIG_VECTORS_BASE=0xffff0000
|
||||
CONFIG_VFP=y
|
||||
CONFIG_VFPv3=y
|
||||
CONFIG_WATCHDOG_CORE=y
|
||||
CONFIG_XPS=y
|
||||
CONFIG_XZ_DEC_ARM=y
|
||||
CONFIG_XZ_DEC_BCJ=y
|
||||
CONFIG_ZBOOT_ROM_BSS=0
|
||||
CONFIG_ZBOOT_ROM_TEXT=0
|
||||
CONFIG_ZLIB_DEFLATE=y
|
||||
CONFIG_ZLIB_INFLATE=y
|
||||
@ -1,111 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
//
|
||||
// Copyright (c) 2019 Mantas Pucka <mantas@8devices.com>
|
||||
// Copyright (c) 2019 Robert Marko <robimarko@gmail.com>
|
||||
//
|
||||
// Driver for IPQ4019 SD/MMC controller's I/O LDO voltage regulator
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/driver.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
#include <linux/regulator/of_regulator.h>
|
||||
|
||||
static const unsigned int ipq4019_vmmc_voltages[] = {
|
||||
1500000, 1800000, 2500000, 3000000,
|
||||
};
|
||||
|
||||
static struct regulator_ops ipq4019_regulator_voltage_ops = {
|
||||
.list_voltage = regulator_list_voltage_table,
|
||||
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
||||
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
||||
};
|
||||
|
||||
static struct regulator_desc vmmc_regulator = {
|
||||
.name = "vmmcq",
|
||||
.ops = &ipq4019_regulator_voltage_ops,
|
||||
.type = REGULATOR_VOLTAGE,
|
||||
.owner = THIS_MODULE,
|
||||
.volt_table = ipq4019_vmmc_voltages,
|
||||
.n_voltages = ARRAY_SIZE(ipq4019_vmmc_voltages),
|
||||
.vsel_reg = 0,
|
||||
.vsel_mask = 0x3,
|
||||
};
|
||||
|
||||
const struct regmap_config ipq4019_vmmcq_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.val_bits = 32,
|
||||
};
|
||||
|
||||
static int ipq4019_regulator_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct regulator_init_data *init_data;
|
||||
struct regulator_config cfg = {};
|
||||
struct regulator_dev *rdev;
|
||||
struct resource *res;
|
||||
struct regmap *rmap;
|
||||
void __iomem *base;
|
||||
|
||||
init_data = of_get_regulator_init_data(dev, dev->of_node,
|
||||
&vmmc_regulator);
|
||||
if (!init_data)
|
||||
return -EINVAL;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
base = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
rmap = devm_regmap_init_mmio(dev, base, &ipq4019_vmmcq_regmap_config);
|
||||
if (IS_ERR(rmap))
|
||||
return PTR_ERR(rmap);
|
||||
|
||||
cfg.dev = dev;
|
||||
cfg.init_data = init_data;
|
||||
cfg.of_node = dev->of_node;
|
||||
cfg.regmap = rmap;
|
||||
|
||||
rdev = devm_regulator_register(dev, &vmmc_regulator, &cfg);
|
||||
if (IS_ERR(rdev)) {
|
||||
dev_err(dev, "Failed to register regulator: %ld\n",
|
||||
PTR_ERR(rdev));
|
||||
return PTR_ERR(rdev);
|
||||
}
|
||||
platform_set_drvdata(pdev, rdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ipq4019_regulator_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct regulator_dev *rdev = platform_get_drvdata(pdev);
|
||||
|
||||
regulator_unregister(rdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id regulator_ipq4019_of_match[] = {
|
||||
{ .compatible = "qcom,ipq4019-vqmmc-regulator", },
|
||||
{},
|
||||
};
|
||||
|
||||
static struct platform_driver ipq4019_regulator_driver = {
|
||||
.probe = ipq4019_regulator_probe,
|
||||
.remove = ipq4019_regulator_remove,
|
||||
.driver = {
|
||||
.name = "regulator-vqmmc-ipq4019",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(regulator_ipq4019_of_match),
|
||||
},
|
||||
};
|
||||
module_platform_driver(ipq4019_regulator_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Mantas Pucka <mantas@8devices.com>");
|
||||
MODULE_DESCRIPTION("IPQ4019 VQMMC voltage regulator");
|
||||
@ -1,47 +0,0 @@
|
||||
From 882fd1577cbe7812ae3a48988180c5f0fda475ca Mon Sep 17 00:00:00 2001
|
||||
From: Miquel Raynal <miquel.raynal@free-electrons.com>
|
||||
Date: Sat, 26 Aug 2017 17:19:15 +0200
|
||||
Subject: [PATCH] mtd: nand: Use standard large page OOB layout when using
|
||||
NAND_ECC_NONE
|
||||
|
||||
Use the core's large page OOB layout functions when not reserving any
|
||||
space for ECC bytes in the OOB layout. Fix ->nand_ooblayout_ecc_lp()
|
||||
to return -ERANGE instead of a zero length in this case.
|
||||
|
||||
Signed-off-by: Miquel Raynal <miquel.raynal@free-electrons.com>
|
||||
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
|
||||
---
|
||||
drivers/mtd/nand/nand_base.c | 15 ++++++++++++++-
|
||||
1 file changed, 14 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/mtd/nand/nand_base.c
|
||||
+++ b/drivers/mtd/nand/nand_base.c
|
||||
@@ -115,7 +115,7 @@ static int nand_ooblayout_ecc_lp(struct
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct nand_ecc_ctrl *ecc = &chip->ecc;
|
||||
|
||||
- if (section)
|
||||
+ if (section || !ecc->total)
|
||||
return -ERANGE;
|
||||
|
||||
oobregion->length = ecc->total;
|
||||
@@ -4712,6 +4712,19 @@ int nand_scan_tail(struct mtd_info *mtd)
|
||||
mtd_set_ooblayout(mtd, &nand_ooblayout_lp_hamming_ops);
|
||||
break;
|
||||
default:
|
||||
+ /*
|
||||
+ * Expose the whole OOB area to users if ECC_NONE
|
||||
+ * is passed. We could do that for all kind of
|
||||
+ * ->oobsize, but we must keep the old large/small
|
||||
+ * page with ECC layout when ->oobsize <= 128 for
|
||||
+ * compatibility reasons.
|
||||
+ */
|
||||
+ if (ecc->mode == NAND_ECC_NONE) {
|
||||
+ mtd_set_ooblayout(mtd,
|
||||
+ &nand_ooblayout_lp_ops);
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
WARN(1, "No oob scheme defined for oobsize %d\n",
|
||||
mtd->oobsize);
|
||||
ret = -EINVAL;
|
||||
@ -1,48 +0,0 @@
|
||||
From eb94555e9e97c9983461214046b4d72c4ab4ba70 Mon Sep 17 00:00:00 2001
|
||||
From: Miquel Raynal <miquel.raynal@free-electrons.com>
|
||||
Date: Thu, 30 Nov 2017 18:01:28 +0100
|
||||
Subject: [PATCH] mtd: nand: use usual return values for the ->erase() hook
|
||||
|
||||
Avoid using specific defined values for checking returned status of the
|
||||
->erase() hook. Instead, use usual negative error values on failure,
|
||||
zero otherwise.
|
||||
|
||||
Signed-off-by: Miquel Raynal <miquel.raynal@free-electrons.com>
|
||||
Acked-by: Masahiro Yamada <yamada.masahiro@socionext.com>
|
||||
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
|
||||
---
|
||||
drivers/mtd/nand/denali.c | 2 +-
|
||||
drivers/mtd/nand/docg4.c | 7 ++++++-
|
||||
drivers/mtd/nand/nand_base.c | 10 ++++++++--
|
||||
3 files changed, 15 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/drivers/mtd/nand/nand_base.c
|
||||
+++ b/drivers/mtd/nand/nand_base.c
|
||||
@@ -2994,11 +2994,17 @@ out:
|
||||
static int single_erase(struct mtd_info *mtd, int page)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
+ int status;
|
||||
+
|
||||
/* Send commands to erase a block */
|
||||
chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);
|
||||
chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);
|
||||
|
||||
- return chip->waitfunc(mtd, chip);
|
||||
+ status = chip->waitfunc(mtd, chip);
|
||||
+ if (status < 0)
|
||||
+ return status;
|
||||
+
|
||||
+ return status & NAND_STATUS_FAIL ? -EIO : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3082,7 +3088,7 @@ int nand_erase_nand(struct mtd_info *mtd
|
||||
status = chip->erase(mtd, page & chip->pagemask);
|
||||
|
||||
/* See if block erase succeeded */
|
||||
- if (status & NAND_STATUS_FAIL) {
|
||||
+ if (status) {
|
||||
pr_debug("%s: failed erase, page 0x%08x\n",
|
||||
__func__, page);
|
||||
instr->state = MTD_ERASE_FAILED;
|
||||
@ -1,409 +0,0 @@
|
||||
From 6b4faeac05bc0b91616b921191cb054d1376f3b4 Mon Sep 17 00:00:00 2001
|
||||
From: Sricharan R <sricharan@codeaurora.org>
|
||||
Date: Mon, 28 Aug 2017 20:30:24 +0530
|
||||
Subject: [PATCH] dmaengine: qcom-bam: Process multiple pending descriptors
|
||||
|
||||
The bam dmaengine has a circular FIFO to which we
|
||||
add hw descriptors that describes the transaction.
|
||||
The FIFO has space for about 4096 hw descriptors.
|
||||
|
||||
Currently we add one descriptor and wait for it to
|
||||
complete with interrupt and then add the next pending
|
||||
descriptor. In this way, the FIFO is underutilized
|
||||
since only one descriptor is processed at a time, although
|
||||
there is space in FIFO for the BAM to process more.
|
||||
|
||||
Instead keep adding descriptors to FIFO till its full,
|
||||
that allows BAM to continue to work on the next descriptor
|
||||
immediately after signalling completion interrupt for the
|
||||
previous descriptor.
|
||||
|
||||
Also when the client has not set the DMA_PREP_INTERRUPT for
|
||||
a descriptor, then do not configure BAM to trigger a interrupt
|
||||
upon completion of that descriptor. This way we get a interrupt
|
||||
only for the descriptor for which DMA_PREP_INTERRUPT was
|
||||
requested and there signal completion of all the previous completed
|
||||
descriptors. So we still do callbacks for all requested descriptors,
|
||||
but just that the number of interrupts are reduced.
|
||||
|
||||
CURRENT:
|
||||
|
||||
------ ------- ---------------
|
||||
|DES 0| |DESC 1| |DESC 2 + INT |
|
||||
------ ------- ---------------
|
||||
| | |
|
||||
| | |
|
||||
INTERRUPT: (INT) (INT) (INT)
|
||||
CALLBACK: (CB) (CB) (CB)
|
||||
|
||||
MTD_SPEEDTEST READ PAGE: 3560 KiB/s
|
||||
MTD_SPEEDTEST WRITE PAGE: 2664 KiB/s
|
||||
IOZONE READ: 2456 KB/s
|
||||
IOZONE WRITE: 1230 KB/s
|
||||
|
||||
bam dma interrupts (after tests): 96508
|
||||
|
||||
CHANGE:
|
||||
|
||||
------ ------- -------------
|
||||
|DES 0| |DESC 1 |DESC 2 + INT |
|
||||
------ ------- --------------
|
||||
|
|
||||
|
|
||||
(INT)
|
||||
(CB for 0, 1, 2)
|
||||
|
||||
MTD_SPEEDTEST READ PAGE: 3860 KiB/s
|
||||
MTD_SPEEDTEST WRITE PAGE: 2837 KiB/s
|
||||
IOZONE READ: 2677 KB/s
|
||||
IOZONE WRITE: 1308 KB/s
|
||||
|
||||
bam dma interrupts (after tests): 58806
|
||||
|
||||
Signed-off-by: Sricharan R <sricharan@codeaurora.org>
|
||||
Reviewed-by: Andy Gross <andy.gross@linaro.org>
|
||||
Tested-by: Abhishek Sahu <absahu@codeaurora.org>
|
||||
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
|
||||
---
|
||||
drivers/dma/qcom/bam_dma.c | 169 +++++++++++++++++++++++++++++----------------
|
||||
1 file changed, 109 insertions(+), 60 deletions(-)
|
||||
|
||||
--- a/drivers/dma/qcom/bam_dma.c
|
||||
+++ b/drivers/dma/qcom/bam_dma.c
|
||||
@@ -46,6 +46,7 @@
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_dma.h>
|
||||
+#include <linux/circ_buf.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
@@ -78,6 +79,8 @@ struct bam_async_desc {
|
||||
|
||||
struct bam_desc_hw *curr_desc;
|
||||
|
||||
+ /* list node for the desc in the bam_chan list of descriptors */
|
||||
+ struct list_head desc_node;
|
||||
enum dma_transfer_direction dir;
|
||||
size_t length;
|
||||
struct bam_desc_hw desc[0];
|
||||
@@ -347,6 +350,8 @@ static const struct reg_offset_data bam_
|
||||
#define BAM_DESC_FIFO_SIZE SZ_32K
|
||||
#define MAX_DESCRIPTORS (BAM_DESC_FIFO_SIZE / sizeof(struct bam_desc_hw) - 1)
|
||||
#define BAM_FIFO_SIZE (SZ_32K - 8)
|
||||
+#define IS_BUSY(chan) (CIRC_SPACE(bchan->tail, bchan->head,\
|
||||
+ MAX_DESCRIPTORS + 1) == 0)
|
||||
|
||||
struct bam_chan {
|
||||
struct virt_dma_chan vc;
|
||||
@@ -356,8 +361,6 @@ struct bam_chan {
|
||||
/* configuration from device tree */
|
||||
u32 id;
|
||||
|
||||
- struct bam_async_desc *curr_txd; /* current running dma */
|
||||
-
|
||||
/* runtime configuration */
|
||||
struct dma_slave_config slave;
|
||||
|
||||
@@ -372,6 +375,8 @@ struct bam_chan {
|
||||
unsigned int initialized; /* is the channel hw initialized? */
|
||||
unsigned int paused; /* is the channel paused? */
|
||||
unsigned int reconfigure; /* new slave config? */
|
||||
+ /* list of descriptors currently processed */
|
||||
+ struct list_head desc_list;
|
||||
|
||||
struct list_head node;
|
||||
};
|
||||
@@ -540,7 +545,7 @@ static void bam_free_chan(struct dma_cha
|
||||
|
||||
vchan_free_chan_resources(to_virt_chan(chan));
|
||||
|
||||
- if (bchan->curr_txd) {
|
||||
+ if (!list_empty(&bchan->desc_list)) {
|
||||
dev_err(bchan->bdev->dev, "Cannot free busy channel\n");
|
||||
goto err;
|
||||
}
|
||||
@@ -633,8 +638,6 @@ static struct dma_async_tx_descriptor *b
|
||||
|
||||
if (flags & DMA_PREP_INTERRUPT)
|
||||
async_desc->flags |= DESC_FLAG_EOT;
|
||||
- else
|
||||
- async_desc->flags |= DESC_FLAG_INT;
|
||||
|
||||
async_desc->num_desc = num_alloc;
|
||||
async_desc->curr_desc = async_desc->desc;
|
||||
@@ -685,28 +688,16 @@ err_out:
|
||||
static int bam_dma_terminate_all(struct dma_chan *chan)
|
||||
{
|
||||
struct bam_chan *bchan = to_bam_chan(chan);
|
||||
+ struct bam_async_desc *async_desc, *tmp;
|
||||
unsigned long flag;
|
||||
LIST_HEAD(head);
|
||||
|
||||
/* remove all transactions, including active transaction */
|
||||
spin_lock_irqsave(&bchan->vc.lock, flag);
|
||||
- /*
|
||||
- * If we have transactions queued, then some might be committed to the
|
||||
- * hardware in the desc fifo. The only way to reset the desc fifo is
|
||||
- * to do a hardware reset (either by pipe or the entire block).
|
||||
- * bam_chan_init_hw() will trigger a pipe reset, and also reinit the
|
||||
- * pipe. If the pipe is left disabled (default state after pipe reset)
|
||||
- * and is accessed by a connected hardware engine, a fatal error in
|
||||
- * the BAM will occur. There is a small window where this could happen
|
||||
- * with bam_chan_init_hw(), but it is assumed that the caller has
|
||||
- * stopped activity on any attached hardware engine. Make sure to do
|
||||
- * this first so that the BAM hardware doesn't cause memory corruption
|
||||
- * by accessing freed resources.
|
||||
- */
|
||||
- if (bchan->curr_txd) {
|
||||
- bam_chan_init_hw(bchan, bchan->curr_txd->dir);
|
||||
- list_add(&bchan->curr_txd->vd.node, &bchan->vc.desc_issued);
|
||||
- bchan->curr_txd = NULL;
|
||||
+ list_for_each_entry_safe(async_desc, tmp,
|
||||
+ &bchan->desc_list, desc_node) {
|
||||
+ list_add(&async_desc->vd.node, &bchan->vc.desc_issued);
|
||||
+ list_del(&async_desc->desc_node);
|
||||
}
|
||||
|
||||
vchan_get_all_descriptors(&bchan->vc, &head);
|
||||
@@ -778,9 +769,9 @@ static int bam_resume(struct dma_chan *c
|
||||
*/
|
||||
static u32 process_channel_irqs(struct bam_device *bdev)
|
||||
{
|
||||
- u32 i, srcs, pipe_stts;
|
||||
+ u32 i, srcs, pipe_stts, offset, avail;
|
||||
unsigned long flags;
|
||||
- struct bam_async_desc *async_desc;
|
||||
+ struct bam_async_desc *async_desc, *tmp;
|
||||
|
||||
srcs = readl_relaxed(bam_addr(bdev, 0, BAM_IRQ_SRCS_EE));
|
||||
|
||||
@@ -800,27 +791,40 @@ static u32 process_channel_irqs(struct b
|
||||
writel_relaxed(pipe_stts, bam_addr(bdev, i, BAM_P_IRQ_CLR));
|
||||
|
||||
spin_lock_irqsave(&bchan->vc.lock, flags);
|
||||
- async_desc = bchan->curr_txd;
|
||||
|
||||
- if (async_desc) {
|
||||
- async_desc->num_desc -= async_desc->xfer_len;
|
||||
- async_desc->curr_desc += async_desc->xfer_len;
|
||||
- bchan->curr_txd = NULL;
|
||||
+ offset = readl_relaxed(bam_addr(bdev, i, BAM_P_SW_OFSTS)) &
|
||||
+ P_SW_OFSTS_MASK;
|
||||
+ offset /= sizeof(struct bam_desc_hw);
|
||||
+
|
||||
+ /* Number of bytes available to read */
|
||||
+ avail = CIRC_CNT(offset, bchan->head, MAX_DESCRIPTORS + 1);
|
||||
+
|
||||
+ list_for_each_entry_safe(async_desc, tmp,
|
||||
+ &bchan->desc_list, desc_node) {
|
||||
+ /* Not enough data to read */
|
||||
+ if (avail < async_desc->xfer_len)
|
||||
+ break;
|
||||
|
||||
/* manage FIFO */
|
||||
bchan->head += async_desc->xfer_len;
|
||||
bchan->head %= MAX_DESCRIPTORS;
|
||||
|
||||
+ async_desc->num_desc -= async_desc->xfer_len;
|
||||
+ async_desc->curr_desc += async_desc->xfer_len;
|
||||
+ avail -= async_desc->xfer_len;
|
||||
+
|
||||
/*
|
||||
- * if complete, process cookie. Otherwise
|
||||
+ * if complete, process cookie. Otherwise
|
||||
* push back to front of desc_issued so that
|
||||
* it gets restarted by the tasklet
|
||||
*/
|
||||
- if (!async_desc->num_desc)
|
||||
+ if (!async_desc->num_desc) {
|
||||
vchan_cookie_complete(&async_desc->vd);
|
||||
- else
|
||||
+ } else {
|
||||
list_add(&async_desc->vd.node,
|
||||
- &bchan->vc.desc_issued);
|
||||
+ &bchan->vc.desc_issued);
|
||||
+ }
|
||||
+ list_del(&async_desc->desc_node);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&bchan->vc.lock, flags);
|
||||
@@ -882,6 +886,7 @@ static enum dma_status bam_tx_status(str
|
||||
struct dma_tx_state *txstate)
|
||||
{
|
||||
struct bam_chan *bchan = to_bam_chan(chan);
|
||||
+ struct bam_async_desc *async_desc;
|
||||
struct virt_dma_desc *vd;
|
||||
int ret;
|
||||
size_t residue = 0;
|
||||
@@ -897,11 +902,17 @@ static enum dma_status bam_tx_status(str
|
||||
|
||||
spin_lock_irqsave(&bchan->vc.lock, flags);
|
||||
vd = vchan_find_desc(&bchan->vc, cookie);
|
||||
- if (vd)
|
||||
+ if (vd) {
|
||||
residue = container_of(vd, struct bam_async_desc, vd)->length;
|
||||
- else if (bchan->curr_txd && bchan->curr_txd->vd.tx.cookie == cookie)
|
||||
- for (i = 0; i < bchan->curr_txd->num_desc; i++)
|
||||
- residue += bchan->curr_txd->curr_desc[i].size;
|
||||
+ } else {
|
||||
+ list_for_each_entry(async_desc, &bchan->desc_list, desc_node) {
|
||||
+ if (async_desc->vd.tx.cookie != cookie)
|
||||
+ continue;
|
||||
+
|
||||
+ for (i = 0; i < async_desc->num_desc; i++)
|
||||
+ residue += async_desc->curr_desc[i].size;
|
||||
+ }
|
||||
+ }
|
||||
|
||||
spin_unlock_irqrestore(&bchan->vc.lock, flags);
|
||||
|
||||
@@ -942,63 +953,86 @@ static void bam_start_dma(struct bam_cha
|
||||
{
|
||||
struct virt_dma_desc *vd = vchan_next_desc(&bchan->vc);
|
||||
struct bam_device *bdev = bchan->bdev;
|
||||
- struct bam_async_desc *async_desc;
|
||||
+ struct bam_async_desc *async_desc = NULL;
|
||||
struct bam_desc_hw *desc;
|
||||
struct bam_desc_hw *fifo = PTR_ALIGN(bchan->fifo_virt,
|
||||
sizeof(struct bam_desc_hw));
|
||||
int ret;
|
||||
+ unsigned int avail;
|
||||
+ struct dmaengine_desc_callback cb;
|
||||
|
||||
lockdep_assert_held(&bchan->vc.lock);
|
||||
|
||||
if (!vd)
|
||||
return;
|
||||
|
||||
- list_del(&vd->node);
|
||||
-
|
||||
- async_desc = container_of(vd, struct bam_async_desc, vd);
|
||||
- bchan->curr_txd = async_desc;
|
||||
-
|
||||
ret = pm_runtime_get_sync(bdev->dev);
|
||||
if (ret < 0)
|
||||
return;
|
||||
|
||||
- /* on first use, initialize the channel hardware */
|
||||
- if (!bchan->initialized)
|
||||
- bam_chan_init_hw(bchan, async_desc->dir);
|
||||
-
|
||||
- /* apply new slave config changes, if necessary */
|
||||
- if (bchan->reconfigure)
|
||||
- bam_apply_new_config(bchan, async_desc->dir);
|
||||
+ while (vd && !IS_BUSY(bchan)) {
|
||||
+ list_del(&vd->node);
|
||||
|
||||
- desc = bchan->curr_txd->curr_desc;
|
||||
+ async_desc = container_of(vd, struct bam_async_desc, vd);
|
||||
|
||||
- if (async_desc->num_desc > MAX_DESCRIPTORS)
|
||||
- async_desc->xfer_len = MAX_DESCRIPTORS;
|
||||
- else
|
||||
- async_desc->xfer_len = async_desc->num_desc;
|
||||
+ /* on first use, initialize the channel hardware */
|
||||
+ if (!bchan->initialized)
|
||||
+ bam_chan_init_hw(bchan, async_desc->dir);
|
||||
|
||||
- /* set any special flags on the last descriptor */
|
||||
- if (async_desc->num_desc == async_desc->xfer_len)
|
||||
- desc[async_desc->xfer_len - 1].flags |=
|
||||
- cpu_to_le16(async_desc->flags);
|
||||
- else
|
||||
- desc[async_desc->xfer_len - 1].flags |=
|
||||
- cpu_to_le16(DESC_FLAG_INT);
|
||||
+ /* apply new slave config changes, if necessary */
|
||||
+ if (bchan->reconfigure)
|
||||
+ bam_apply_new_config(bchan, async_desc->dir);
|
||||
+
|
||||
+ desc = async_desc->curr_desc;
|
||||
+ avail = CIRC_SPACE(bchan->tail, bchan->head,
|
||||
+ MAX_DESCRIPTORS + 1);
|
||||
+
|
||||
+ if (async_desc->num_desc > avail)
|
||||
+ async_desc->xfer_len = avail;
|
||||
+ else
|
||||
+ async_desc->xfer_len = async_desc->num_desc;
|
||||
|
||||
- if (bchan->tail + async_desc->xfer_len > MAX_DESCRIPTORS) {
|
||||
- u32 partial = MAX_DESCRIPTORS - bchan->tail;
|
||||
+ /* set any special flags on the last descriptor */
|
||||
+ if (async_desc->num_desc == async_desc->xfer_len)
|
||||
+ desc[async_desc->xfer_len - 1].flags |=
|
||||
+ cpu_to_le16(async_desc->flags);
|
||||
|
||||
- memcpy(&fifo[bchan->tail], desc,
|
||||
- partial * sizeof(struct bam_desc_hw));
|
||||
- memcpy(fifo, &desc[partial], (async_desc->xfer_len - partial) *
|
||||
+ vd = vchan_next_desc(&bchan->vc);
|
||||
+
|
||||
+ dmaengine_desc_get_callback(&async_desc->vd.tx, &cb);
|
||||
+
|
||||
+ /*
|
||||
+ * An interrupt is generated at this desc, if
|
||||
+ * - FIFO is FULL.
|
||||
+ * - No more descriptors to add.
|
||||
+ * - If a callback completion was requested for this DESC,
|
||||
+ * In this case, BAM will deliver the completion callback
|
||||
+ * for this desc and continue processing the next desc.
|
||||
+ */
|
||||
+ if (((avail <= async_desc->xfer_len) || !vd ||
|
||||
+ dmaengine_desc_callback_valid(&cb)) &&
|
||||
+ !(async_desc->flags & DESC_FLAG_EOT))
|
||||
+ desc[async_desc->xfer_len - 1].flags |=
|
||||
+ cpu_to_le16(DESC_FLAG_INT);
|
||||
+
|
||||
+ if (bchan->tail + async_desc->xfer_len > MAX_DESCRIPTORS) {
|
||||
+ u32 partial = MAX_DESCRIPTORS - bchan->tail;
|
||||
+
|
||||
+ memcpy(&fifo[bchan->tail], desc,
|
||||
+ partial * sizeof(struct bam_desc_hw));
|
||||
+ memcpy(fifo, &desc[partial],
|
||||
+ (async_desc->xfer_len - partial) *
|
||||
sizeof(struct bam_desc_hw));
|
||||
- } else {
|
||||
- memcpy(&fifo[bchan->tail], desc,
|
||||
- async_desc->xfer_len * sizeof(struct bam_desc_hw));
|
||||
- }
|
||||
+ } else {
|
||||
+ memcpy(&fifo[bchan->tail], desc,
|
||||
+ async_desc->xfer_len *
|
||||
+ sizeof(struct bam_desc_hw));
|
||||
+ }
|
||||
|
||||
- bchan->tail += async_desc->xfer_len;
|
||||
- bchan->tail %= MAX_DESCRIPTORS;
|
||||
+ bchan->tail += async_desc->xfer_len;
|
||||
+ bchan->tail %= MAX_DESCRIPTORS;
|
||||
+ list_add_tail(&async_desc->desc_node, &bchan->desc_list);
|
||||
+ }
|
||||
|
||||
/* ensure descriptor writes and dma start not reordered */
|
||||
wmb();
|
||||
@@ -1027,7 +1061,7 @@ static void dma_tasklet(unsigned long da
|
||||
bchan = &bdev->channels[i];
|
||||
spin_lock_irqsave(&bchan->vc.lock, flags);
|
||||
|
||||
- if (!list_empty(&bchan->vc.desc_issued) && !bchan->curr_txd)
|
||||
+ if (!list_empty(&bchan->vc.desc_issued) && !IS_BUSY(bchan))
|
||||
bam_start_dma(bchan);
|
||||
spin_unlock_irqrestore(&bchan->vc.lock, flags);
|
||||
}
|
||||
@@ -1048,7 +1082,7 @@ static void bam_issue_pending(struct dma
|
||||
spin_lock_irqsave(&bchan->vc.lock, flags);
|
||||
|
||||
/* if work pending and idle, start a transaction */
|
||||
- if (vchan_issue_pending(&bchan->vc) && !bchan->curr_txd)
|
||||
+ if (vchan_issue_pending(&bchan->vc) && !IS_BUSY(bchan))
|
||||
bam_start_dma(bchan);
|
||||
|
||||
spin_unlock_irqrestore(&bchan->vc.lock, flags);
|
||||
@@ -1152,6 +1186,7 @@ static void bam_channel_init(struct bam_
|
||||
|
||||
vchan_init(&bchan->vc, &bdev->common);
|
||||
bchan->vc.desc_free = bam_dma_free_desc;
|
||||
+ INIT_LIST_HEAD(&bchan->desc_list);
|
||||
}
|
||||
|
||||
static const struct of_device_id bam_of_match[] = {
|
||||
@ -1,89 +0,0 @@
|
||||
From 8c4cdce8b1ab044a2ee1d86d5a086f67e32b3c10 Mon Sep 17 00:00:00 2001
|
||||
From: Abhishek Sahu <absahu@codeaurora.org>
|
||||
Date: Mon, 25 Sep 2017 13:21:25 +0530
|
||||
Subject: [PATCH 2/7] mtd: nand: qcom: add command elements in BAM transaction
|
||||
|
||||
All the QPIC register read/write through BAM DMA requires
|
||||
command descriptor which contains the array of command elements.
|
||||
|
||||
Reviewed-by: Archit Taneja <architt@codeaurora.org>
|
||||
Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
|
||||
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
|
||||
---
|
||||
drivers/mtd/nand/qcom_nandc.c | 19 ++++++++++++++++++-
|
||||
1 file changed, 18 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/mtd/nand/qcom_nandc.c
|
||||
+++ b/drivers/mtd/nand/qcom_nandc.c
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/delay.h>
|
||||
+#include <linux/dma/qcom_bam_dma.h>
|
||||
|
||||
/* NANDc reg offsets */
|
||||
#define NAND_FLASH_CMD 0x00
|
||||
@@ -199,6 +200,7 @@ nandc_set_reg(nandc, NAND_READ_LOCATION_
|
||||
*/
|
||||
#define dev_cmd_reg_addr(nandc, reg) ((nandc)->props->dev_cmd_reg_start + (reg))
|
||||
|
||||
+#define QPIC_PER_CW_CMD_ELEMENTS 32
|
||||
#define QPIC_PER_CW_CMD_SGL 32
|
||||
#define QPIC_PER_CW_DATA_SGL 8
|
||||
|
||||
@@ -221,8 +223,13 @@ nandc_set_reg(nandc, NAND_READ_LOCATION_
|
||||
/*
|
||||
* This data type corresponds to the BAM transaction which will be used for all
|
||||
* NAND transfers.
|
||||
+ * @bam_ce - the array of BAM command elements
|
||||
* @cmd_sgl - sgl for NAND BAM command pipe
|
||||
* @data_sgl - sgl for NAND BAM consumer/producer pipe
|
||||
+ * @bam_ce_pos - the index in bam_ce which is available for next sgl
|
||||
+ * @bam_ce_start - the index in bam_ce which marks the start position ce
|
||||
+ * for current sgl. It will be used for size calculation
|
||||
+ * for current sgl
|
||||
* @cmd_sgl_pos - current index in command sgl.
|
||||
* @cmd_sgl_start - start index in command sgl.
|
||||
* @tx_sgl_pos - current index in data sgl for tx.
|
||||
@@ -231,8 +238,11 @@ nandc_set_reg(nandc, NAND_READ_LOCATION_
|
||||
* @rx_sgl_start - start index in data sgl for rx.
|
||||
*/
|
||||
struct bam_transaction {
|
||||
+ struct bam_cmd_element *bam_ce;
|
||||
struct scatterlist *cmd_sgl;
|
||||
struct scatterlist *data_sgl;
|
||||
+ u32 bam_ce_pos;
|
||||
+ u32 bam_ce_start;
|
||||
u32 cmd_sgl_pos;
|
||||
u32 cmd_sgl_start;
|
||||
u32 tx_sgl_pos;
|
||||
@@ -464,7 +474,8 @@ alloc_bam_transaction(struct qcom_nand_c
|
||||
|
||||
bam_txn_size =
|
||||
sizeof(*bam_txn) + num_cw *
|
||||
- ((sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL) +
|
||||
+ ((sizeof(*bam_txn->bam_ce) * QPIC_PER_CW_CMD_ELEMENTS) +
|
||||
+ (sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL) +
|
||||
(sizeof(*bam_txn->data_sgl) * QPIC_PER_CW_DATA_SGL));
|
||||
|
||||
bam_txn_buf = devm_kzalloc(nandc->dev, bam_txn_size, GFP_KERNEL);
|
||||
@@ -474,6 +485,10 @@ alloc_bam_transaction(struct qcom_nand_c
|
||||
bam_txn = bam_txn_buf;
|
||||
bam_txn_buf += sizeof(*bam_txn);
|
||||
|
||||
+ bam_txn->bam_ce = bam_txn_buf;
|
||||
+ bam_txn_buf +=
|
||||
+ sizeof(*bam_txn->bam_ce) * QPIC_PER_CW_CMD_ELEMENTS * num_cw;
|
||||
+
|
||||
bam_txn->cmd_sgl = bam_txn_buf;
|
||||
bam_txn_buf +=
|
||||
sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL * num_cw;
|
||||
@@ -491,6 +506,8 @@ static void clear_bam_transaction(struct
|
||||
if (!nandc->props->is_bam)
|
||||
return;
|
||||
|
||||
+ bam_txn->bam_ce_pos = 0;
|
||||
+ bam_txn->bam_ce_start = 0;
|
||||
bam_txn->cmd_sgl_pos = 0;
|
||||
bam_txn->cmd_sgl_start = 0;
|
||||
bam_txn->tx_sgl_pos = 0;
|
||||
@ -1,201 +0,0 @@
|
||||
From 8d6b6d7e135e9bbfc923d34a45cb0e72695e63ed Mon Sep 17 00:00:00 2001
|
||||
From: Abhishek Sahu <absahu@codeaurora.org>
|
||||
Date: Mon, 25 Sep 2017 13:21:26 +0530
|
||||
Subject: [PATCH 3/7] mtd: nand: qcom: support for command descriptor formation
|
||||
|
||||
1. Add the function for command descriptor preparation which will
|
||||
be used only by BAM DMA and it will form the DMA descriptors
|
||||
containing command elements
|
||||
2. DMA_PREP_CMD flag should be used for forming command DMA
|
||||
descriptors
|
||||
|
||||
Reviewed-by: Archit Taneja <architt@codeaurora.org>
|
||||
Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
|
||||
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
|
||||
---
|
||||
drivers/mtd/nand/qcom_nandc.c | 108 +++++++++++++++++++++++++++++++++++-------
|
||||
1 file changed, 92 insertions(+), 16 deletions(-)
|
||||
|
||||
--- a/drivers/mtd/nand/qcom_nandc.c
|
||||
+++ b/drivers/mtd/nand/qcom_nandc.c
|
||||
@@ -200,6 +200,14 @@ nandc_set_reg(nandc, NAND_READ_LOCATION_
|
||||
*/
|
||||
#define dev_cmd_reg_addr(nandc, reg) ((nandc)->props->dev_cmd_reg_start + (reg))
|
||||
|
||||
+/* Returns the NAND register physical address */
|
||||
+#define nandc_reg_phys(chip, offset) ((chip)->base_phys + (offset))
|
||||
+
|
||||
+/* Returns the dma address for reg read buffer */
|
||||
+#define reg_buf_dma_addr(chip, vaddr) \
|
||||
+ ((chip)->reg_read_dma + \
|
||||
+ ((uint8_t *)(vaddr) - (uint8_t *)(chip)->reg_read_buf))
|
||||
+
|
||||
#define QPIC_PER_CW_CMD_ELEMENTS 32
|
||||
#define QPIC_PER_CW_CMD_SGL 32
|
||||
#define QPIC_PER_CW_DATA_SGL 8
|
||||
@@ -317,7 +325,8 @@ struct nandc_regs {
|
||||
* controller
|
||||
* @dev: parent device
|
||||
* @base: MMIO base
|
||||
- * @base_dma: physical base address of controller registers
|
||||
+ * @base_phys: physical base address of controller registers
|
||||
+ * @base_dma: dma base address of controller registers
|
||||
* @core_clk: controller clock
|
||||
* @aon_clk: another controller clock
|
||||
*
|
||||
@@ -350,6 +359,7 @@ struct qcom_nand_controller {
|
||||
struct device *dev;
|
||||
|
||||
void __iomem *base;
|
||||
+ phys_addr_t base_phys;
|
||||
dma_addr_t base_dma;
|
||||
|
||||
struct clk *core_clk;
|
||||
@@ -753,6 +763,66 @@ static int prepare_bam_async_desc(struct
|
||||
}
|
||||
|
||||
/*
|
||||
+ * Prepares the command descriptor for BAM DMA which will be used for NAND
|
||||
+ * register reads and writes. The command descriptor requires the command
|
||||
+ * to be formed in command element type so this function uses the command
|
||||
+ * element from bam transaction ce array and fills the same with required
|
||||
+ * data. A single SGL can contain multiple command elements so
|
||||
+ * NAND_BAM_NEXT_SGL will be used for starting the separate SGL
|
||||
+ * after the current command element.
|
||||
+ */
|
||||
+static int prep_bam_dma_desc_cmd(struct qcom_nand_controller *nandc, bool read,
|
||||
+ int reg_off, const void *vaddr,
|
||||
+ int size, unsigned int flags)
|
||||
+{
|
||||
+ int bam_ce_size;
|
||||
+ int i, ret;
|
||||
+ struct bam_cmd_element *bam_ce_buffer;
|
||||
+ struct bam_transaction *bam_txn = nandc->bam_txn;
|
||||
+
|
||||
+ bam_ce_buffer = &bam_txn->bam_ce[bam_txn->bam_ce_pos];
|
||||
+
|
||||
+ /* fill the command desc */
|
||||
+ for (i = 0; i < size; i++) {
|
||||
+ if (read)
|
||||
+ bam_prep_ce(&bam_ce_buffer[i],
|
||||
+ nandc_reg_phys(nandc, reg_off + 4 * i),
|
||||
+ BAM_READ_COMMAND,
|
||||
+ reg_buf_dma_addr(nandc,
|
||||
+ (__le32 *)vaddr + i));
|
||||
+ else
|
||||
+ bam_prep_ce_le32(&bam_ce_buffer[i],
|
||||
+ nandc_reg_phys(nandc, reg_off + 4 * i),
|
||||
+ BAM_WRITE_COMMAND,
|
||||
+ *((__le32 *)vaddr + i));
|
||||
+ }
|
||||
+
|
||||
+ bam_txn->bam_ce_pos += size;
|
||||
+
|
||||
+ /* use the separate sgl after this command */
|
||||
+ if (flags & NAND_BAM_NEXT_SGL) {
|
||||
+ bam_ce_buffer = &bam_txn->bam_ce[bam_txn->bam_ce_start];
|
||||
+ bam_ce_size = (bam_txn->bam_ce_pos -
|
||||
+ bam_txn->bam_ce_start) *
|
||||
+ sizeof(struct bam_cmd_element);
|
||||
+ sg_set_buf(&bam_txn->cmd_sgl[bam_txn->cmd_sgl_pos],
|
||||
+ bam_ce_buffer, bam_ce_size);
|
||||
+ bam_txn->cmd_sgl_pos++;
|
||||
+ bam_txn->bam_ce_start = bam_txn->bam_ce_pos;
|
||||
+
|
||||
+ if (flags & NAND_BAM_NWD) {
|
||||
+ ret = prepare_bam_async_desc(nandc, nandc->cmd_chan,
|
||||
+ DMA_PREP_FENCE |
|
||||
+ DMA_PREP_CMD);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
* Prepares the data descriptor for BAM DMA which will be used for NAND
|
||||
* data reads and writes.
|
||||
*/
|
||||
@@ -870,19 +940,22 @@ static int read_reg_dma(struct qcom_nand
|
||||
{
|
||||
bool flow_control = false;
|
||||
void *vaddr;
|
||||
- int size;
|
||||
|
||||
- if (first == NAND_READ_ID || first == NAND_FLASH_STATUS)
|
||||
- flow_control = true;
|
||||
+ vaddr = nandc->reg_read_buf + nandc->reg_read_pos;
|
||||
+ nandc->reg_read_pos += num_regs;
|
||||
|
||||
if (first == NAND_DEV_CMD_VLD || first == NAND_DEV_CMD1)
|
||||
first = dev_cmd_reg_addr(nandc, first);
|
||||
|
||||
- size = num_regs * sizeof(u32);
|
||||
- vaddr = nandc->reg_read_buf + nandc->reg_read_pos;
|
||||
- nandc->reg_read_pos += num_regs;
|
||||
+ if (nandc->props->is_bam)
|
||||
+ return prep_bam_dma_desc_cmd(nandc, true, first, vaddr,
|
||||
+ num_regs, flags);
|
||||
+
|
||||
+ if (first == NAND_READ_ID || first == NAND_FLASH_STATUS)
|
||||
+ flow_control = true;
|
||||
|
||||
- return prep_adm_dma_desc(nandc, true, first, vaddr, size, flow_control);
|
||||
+ return prep_adm_dma_desc(nandc, true, first, vaddr,
|
||||
+ num_regs * sizeof(u32), flow_control);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -899,13 +972,9 @@ static int write_reg_dma(struct qcom_nan
|
||||
bool flow_control = false;
|
||||
struct nandc_regs *regs = nandc->regs;
|
||||
void *vaddr;
|
||||
- int size;
|
||||
|
||||
vaddr = offset_to_nandc_reg(regs, first);
|
||||
|
||||
- if (first == NAND_FLASH_CMD)
|
||||
- flow_control = true;
|
||||
-
|
||||
if (first == NAND_ERASED_CW_DETECT_CFG) {
|
||||
if (flags & NAND_ERASED_CW_SET)
|
||||
vaddr = ®s->erased_cw_detect_cfg_set;
|
||||
@@ -922,10 +991,15 @@ static int write_reg_dma(struct qcom_nan
|
||||
if (first == NAND_DEV_CMD_VLD_RESTORE || first == NAND_DEV_CMD_VLD)
|
||||
first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD);
|
||||
|
||||
- size = num_regs * sizeof(u32);
|
||||
+ if (nandc->props->is_bam)
|
||||
+ return prep_bam_dma_desc_cmd(nandc, false, first, vaddr,
|
||||
+ num_regs, flags);
|
||||
+
|
||||
+ if (first == NAND_FLASH_CMD)
|
||||
+ flow_control = true;
|
||||
|
||||
- return prep_adm_dma_desc(nandc, false, first, vaddr, size,
|
||||
- flow_control);
|
||||
+ return prep_adm_dma_desc(nandc, false, first, vaddr,
|
||||
+ num_regs * sizeof(u32), flow_control);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1189,7 +1263,8 @@ static int submit_descs(struct qcom_nand
|
||||
}
|
||||
|
||||
if (bam_txn->cmd_sgl_pos > bam_txn->cmd_sgl_start) {
|
||||
- r = prepare_bam_async_desc(nandc, nandc->cmd_chan, 0);
|
||||
+ r = prepare_bam_async_desc(nandc, nandc->cmd_chan,
|
||||
+ DMA_PREP_CMD);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
@@ -2728,6 +2803,7 @@ static int qcom_nandc_probe(struct platf
|
||||
if (IS_ERR(nandc->base))
|
||||
return PTR_ERR(nandc->base);
|
||||
|
||||
+ nandc->base_phys = res->start;
|
||||
nandc->base_dma = phys_to_dma(dev, (phys_addr_t)res->start);
|
||||
|
||||
nandc->core_clk = devm_clk_get(dev, "core");
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,94 +0,0 @@
|
||||
From 25f815f66a141436df8a4c45e5d2765272aea2ac Mon Sep 17 00:00:00 2001
|
||||
From: Boris Brezillon <boris.brezillon@free-electrons.com>
|
||||
Date: Thu, 30 Nov 2017 18:01:30 +0100
|
||||
Subject: [PATCH 5/7] mtd: nand: force drivers to explicitly send READ/PROG
|
||||
commands
|
||||
|
||||
The core currently send the READ0 and SEQIN+PAGEPROG commands in
|
||||
nand_do_read/write_ops(). This is inconsistent with
|
||||
->read/write_oob[_raw]() hooks behavior which are expected to send
|
||||
these commands.
|
||||
|
||||
There's already a flag (NAND_ECC_CUSTOM_PAGE_ACCESS) to inform the core
|
||||
that a specific controller wants to send the READ/SEQIN+PAGEPROG
|
||||
commands on its own, but it's an opt-in flag, and existing drivers are
|
||||
unlikely to be updated to pass it.
|
||||
|
||||
Moreover, some controllers cannot dissociate the READ/PAGEPROG commands
|
||||
from the associated data transfer and ECC engine activation, and
|
||||
developers have to hack things in their ->cmdfunc() implementation to
|
||||
handle such complex cases, or have to accept the perf penalty of sending
|
||||
twice the same command.
|
||||
To address this problem we are planning on adding a new interface which
|
||||
is passed all information about a NAND operation (including the amount
|
||||
of data to transfer) and replacing all calls to ->cmdfunc() to calls to
|
||||
this new ->exec_op() hook. But, in order to do that, we need to have all
|
||||
->cmdfunc() calls placed near their associated ->read/write_buf/byte()
|
||||
calls.
|
||||
|
||||
Modify the core and relevant drivers to make NAND_ECC_CUSTOM_PAGE_ACCESS
|
||||
the default case, and remove this flag.
|
||||
|
||||
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
|
||||
[miquel.raynal@free-electrons.com: tested, fixed and rebased on nand/next]
|
||||
Signed-off-by: Miquel Raynal <miquel.raynal@free-electrons.com>
|
||||
Acked-by: Masahiro Yamada <yamada.masahiro@socionext.com>
|
||||
---
|
||||
drivers/mtd/nand/qcom_nandc.c | 11 +++++++++++
|
||||
1 file changed, 11 insertions(+)
|
||||
|
||||
--- a/drivers/mtd/nand/qcom_nandc.c
|
||||
+++ b/drivers/mtd/nand/qcom_nandc.c
|
||||
@@ -1727,6 +1727,7 @@ static int qcom_nandc_read_page(struct m
|
||||
u8 *data_buf, *oob_buf = NULL;
|
||||
int ret;
|
||||
|
||||
+ nand_read_page_op(chip, page, 0, NULL, 0);
|
||||
data_buf = buf;
|
||||
oob_buf = oob_required ? chip->oob_poi : NULL;
|
||||
|
||||
@@ -1752,6 +1753,7 @@ static int qcom_nandc_read_page_raw(stru
|
||||
int i, ret;
|
||||
int read_loc;
|
||||
|
||||
+ nand_read_page_op(chip, page, 0, NULL, 0);
|
||||
data_buf = buf;
|
||||
oob_buf = chip->oob_poi;
|
||||
|
||||
@@ -1852,6 +1854,8 @@ static int qcom_nandc_write_page(struct
|
||||
u8 *data_buf, *oob_buf;
|
||||
int i, ret;
|
||||
|
||||
+ nand_prog_page_begin_op(chip, page, 0, NULL, 0);
|
||||
+
|
||||
clear_read_regs(nandc);
|
||||
clear_bam_transaction(nandc);
|
||||
|
||||
@@ -1904,6 +1908,9 @@ static int qcom_nandc_write_page(struct
|
||||
|
||||
free_descs(nandc);
|
||||
|
||||
+ if (!ret)
|
||||
+ ret = nand_prog_page_end_op(chip);
|
||||
+
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1918,6 +1925,7 @@ static int qcom_nandc_write_page_raw(str
|
||||
u8 *data_buf, *oob_buf;
|
||||
int i, ret;
|
||||
|
||||
+ nand_prog_page_begin_op(chip, page, 0, NULL, 0);
|
||||
clear_read_regs(nandc);
|
||||
clear_bam_transaction(nandc);
|
||||
|
||||
@@ -1972,6 +1980,9 @@ static int qcom_nandc_write_page_raw(str
|
||||
|
||||
free_descs(nandc);
|
||||
|
||||
+ if (!ret)
|
||||
+ ret = nand_prog_page_end_op(chip);
|
||||
+
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1,31 +0,0 @@
|
||||
From: Eneas U de Queiroz <cotequeiroz@gmail.com>
|
||||
Subject: [PATCH] crypto: qce - add CRYPTO_ALG_KERN_DRIVER_ONLY flag
|
||||
|
||||
Set the CRYPTO_ALG_KERN_DRIVER_ONLY flag to all algorithms exposed by
|
||||
the qce driver, since they are all hardware accelerated, accessible
|
||||
through a kernel driver only, and not available directly to userspace.
|
||||
|
||||
Signed-off-by: Eneas U de Queiroz <cotequeiroz@gmail.com>
|
||||
|
||||
--- a/drivers/crypto/qce/ablkcipher.c
|
||||
+++ b/drivers/crypto/qce/ablkcipher.c
|
||||
@@ -373,7 +373,7 @@ static int qce_ablkcipher_register_one(c
|
||||
|
||||
alg->cra_priority = 300;
|
||||
alg->cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC |
|
||||
- CRYPTO_ALG_NEED_FALLBACK;
|
||||
+ CRYPTO_ALG_NEED_FALLBACK | CRYPTO_ALG_KERN_DRIVER_ONLY;
|
||||
alg->cra_ctxsize = sizeof(struct qce_cipher_ctx);
|
||||
alg->cra_alignmask = 0;
|
||||
alg->cra_type = &crypto_ablkcipher_type;
|
||||
--- a/drivers/crypto/qce/sha.c
|
||||
+++ b/drivers/crypto/qce/sha.c
|
||||
@@ -526,7 +526,7 @@ static int qce_ahash_register_one(const
|
||||
base = &alg->halg.base;
|
||||
base->cra_blocksize = def->blocksize;
|
||||
base->cra_priority = 300;
|
||||
- base->cra_flags = CRYPTO_ALG_ASYNC;
|
||||
+ base->cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY;
|
||||
base->cra_ctxsize = sizeof(struct qce_sha_ctx);
|
||||
base->cra_alignmask = 0;
|
||||
base->cra_module = THIS_MODULE;
|
||||
@ -1,979 +0,0 @@
|
||||
From f441873642eebf20566c18d2966a8cd4b433ec1c Mon Sep 17 00:00:00 2001
|
||||
From: Ard Biesheuvel <ardb@kernel.org>
|
||||
Date: Tue, 5 Nov 2019 14:28:17 +0100
|
||||
Subject: [PATCH] crypto: qce - switch to skcipher API
|
||||
|
||||
Commit 7a7ffe65c8c5 ("crypto: skcipher - Add top-level skcipher interface")
|
||||
dated 20 august 2015 introduced the new skcipher API which is supposed to
|
||||
replace both blkcipher and ablkcipher. While all consumers of the API have
|
||||
been converted long ago, some producers of the ablkcipher remain, forcing
|
||||
us to keep the ablkcipher support routines alive, along with the matching
|
||||
code to expose [a]blkciphers via the skcipher API.
|
||||
|
||||
So switch this driver to the skcipher API, allowing us to finally drop the
|
||||
blkcipher code in the near future.
|
||||
|
||||
Reviewed-by: Stanimir Varbanov <stanimir.varbanov@linaro.org>
|
||||
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
|
||||
Backported-to-4.19-by: Eneas U de Queiroz <cotequeiroz@gmail.com>
|
||||
|
||||
--- a/drivers/crypto/qce/Makefile
|
||||
+++ b/drivers/crypto/qce/Makefile
|
||||
@@ -4,4 +4,4 @@ qcrypto-objs := core.o \
|
||||
common.o \
|
||||
dma.o \
|
||||
sha.o \
|
||||
- ablkcipher.o
|
||||
+ skcipher.o
|
||||
--- a/drivers/crypto/qce/cipher.h
|
||||
+++ b/drivers/crypto/qce/cipher.h
|
||||
@@ -53,12 +53,12 @@ struct qce_cipher_reqctx {
|
||||
unsigned int cryptlen;
|
||||
};
|
||||
|
||||
-static inline struct qce_alg_template *to_cipher_tmpl(struct crypto_tfm *tfm)
|
||||
+static inline struct qce_alg_template *to_cipher_tmpl(struct crypto_skcipher *tfm)
|
||||
{
|
||||
- struct crypto_alg *alg = tfm->__crt_alg;
|
||||
- return container_of(alg, struct qce_alg_template, alg.crypto);
|
||||
+ struct skcipher_alg *alg = crypto_skcipher_alg(tfm);
|
||||
+ return container_of(alg, struct qce_alg_template, alg.skcipher);
|
||||
}
|
||||
|
||||
-extern const struct qce_algo_ops ablkcipher_ops;
|
||||
+extern const struct qce_algo_ops skcipher_ops;
|
||||
|
||||
#endif /* _CIPHER_H_ */
|
||||
--- a/drivers/crypto/qce/common.c
|
||||
+++ b/drivers/crypto/qce/common.c
|
||||
@@ -312,13 +312,13 @@ go_proc:
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static int qce_setup_regs_ablkcipher(struct crypto_async_request *async_req,
|
||||
+static int qce_setup_regs_skcipher(struct crypto_async_request *async_req,
|
||||
u32 totallen, u32 offset)
|
||||
{
|
||||
- struct ablkcipher_request *req = ablkcipher_request_cast(async_req);
|
||||
- struct qce_cipher_reqctx *rctx = ablkcipher_request_ctx(req);
|
||||
+ struct skcipher_request *req = skcipher_request_cast(async_req);
|
||||
+ struct qce_cipher_reqctx *rctx = skcipher_request_ctx(req);
|
||||
struct qce_cipher_ctx *ctx = crypto_tfm_ctx(async_req->tfm);
|
||||
- struct qce_alg_template *tmpl = to_cipher_tmpl(async_req->tfm);
|
||||
+ struct qce_alg_template *tmpl = to_cipher_tmpl(crypto_skcipher_reqtfm(req));
|
||||
struct qce_device *qce = tmpl->qce;
|
||||
__be32 enckey[QCE_MAX_CIPHER_KEY_SIZE / sizeof(__be32)] = {0};
|
||||
__be32 enciv[QCE_MAX_IV_SIZE / sizeof(__be32)] = {0};
|
||||
@@ -397,8 +397,8 @@ int qce_start(struct crypto_async_reques
|
||||
u32 offset)
|
||||
{
|
||||
switch (type) {
|
||||
- case CRYPTO_ALG_TYPE_ABLKCIPHER:
|
||||
- return qce_setup_regs_ablkcipher(async_req, totallen, offset);
|
||||
+ case CRYPTO_ALG_TYPE_SKCIPHER:
|
||||
+ return qce_setup_regs_skcipher(async_req, totallen, offset);
|
||||
case CRYPTO_ALG_TYPE_AHASH:
|
||||
return qce_setup_regs_ahash(async_req, totallen, offset);
|
||||
default:
|
||||
--- a/drivers/crypto/qce/common.h
|
||||
+++ b/drivers/crypto/qce/common.h
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <linux/types.h>
|
||||
#include <crypto/aes.h>
|
||||
#include <crypto/hash.h>
|
||||
+#include <crypto/internal/skcipher.h>
|
||||
|
||||
/* key size in bytes */
|
||||
#define QCE_SHA_HMAC_KEY_SIZE 64
|
||||
@@ -87,7 +88,7 @@ struct qce_alg_template {
|
||||
unsigned long alg_flags;
|
||||
const u32 *std_iv;
|
||||
union {
|
||||
- struct crypto_alg crypto;
|
||||
+ struct skcipher_alg skcipher;
|
||||
struct ahash_alg ahash;
|
||||
} alg;
|
||||
struct qce_device *qce;
|
||||
--- a/drivers/crypto/qce/core.c
|
||||
+++ b/drivers/crypto/qce/core.c
|
||||
@@ -29,7 +29,7 @@
|
||||
#define QCE_QUEUE_LENGTH 1
|
||||
|
||||
static const struct qce_algo_ops *qce_ops[] = {
|
||||
- &ablkcipher_ops,
|
||||
+ &skcipher_ops,
|
||||
&ahash_ops,
|
||||
};
|
||||
|
||||
--- a/drivers/crypto/qce/ablkcipher.c
|
||||
+++ /dev/null
|
||||
@@ -1,434 +0,0 @@
|
||||
-/*
|
||||
- * Copyright (c) 2010-2014, The Linux Foundation. All rights reserved.
|
||||
- *
|
||||
- * This program is free software; you can redistribute it and/or modify
|
||||
- * it under the terms of the GNU General Public License version 2 and
|
||||
- * only version 2 as published by the Free Software Foundation.
|
||||
- *
|
||||
- * This program is distributed in the hope that it will be useful,
|
||||
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
- * GNU General Public License for more details.
|
||||
- */
|
||||
-
|
||||
-#include <linux/device.h>
|
||||
-#include <linux/interrupt.h>
|
||||
-#include <linux/types.h>
|
||||
-#include <crypto/aes.h>
|
||||
-#include <crypto/des.h>
|
||||
-#include <crypto/internal/skcipher.h>
|
||||
-
|
||||
-#include "cipher.h"
|
||||
-
|
||||
-static LIST_HEAD(ablkcipher_algs);
|
||||
-
|
||||
-static void qce_ablkcipher_done(void *data)
|
||||
-{
|
||||
- struct crypto_async_request *async_req = data;
|
||||
- struct ablkcipher_request *req = ablkcipher_request_cast(async_req);
|
||||
- struct qce_cipher_reqctx *rctx = ablkcipher_request_ctx(req);
|
||||
- struct qce_alg_template *tmpl = to_cipher_tmpl(async_req->tfm);
|
||||
- struct qce_device *qce = tmpl->qce;
|
||||
- enum dma_data_direction dir_src, dir_dst;
|
||||
- u32 status;
|
||||
- int error;
|
||||
- bool diff_dst;
|
||||
-
|
||||
- diff_dst = (req->src != req->dst) ? true : false;
|
||||
- dir_src = diff_dst ? DMA_TO_DEVICE : DMA_BIDIRECTIONAL;
|
||||
- dir_dst = diff_dst ? DMA_FROM_DEVICE : DMA_BIDIRECTIONAL;
|
||||
-
|
||||
- error = qce_dma_terminate_all(&qce->dma);
|
||||
- if (error)
|
||||
- dev_dbg(qce->dev, "ablkcipher dma termination error (%d)\n",
|
||||
- error);
|
||||
-
|
||||
- if (diff_dst)
|
||||
- dma_unmap_sg(qce->dev, rctx->src_sg, rctx->src_nents, dir_src);
|
||||
- dma_unmap_sg(qce->dev, rctx->dst_sg, rctx->dst_nents, dir_dst);
|
||||
-
|
||||
- sg_free_table(&rctx->dst_tbl);
|
||||
-
|
||||
- error = qce_check_status(qce, &status);
|
||||
- if (error < 0)
|
||||
- dev_dbg(qce->dev, "ablkcipher operation error (%x)\n", status);
|
||||
-
|
||||
- qce->async_req_done(tmpl->qce, error);
|
||||
-}
|
||||
-
|
||||
-static int
|
||||
-qce_ablkcipher_async_req_handle(struct crypto_async_request *async_req)
|
||||
-{
|
||||
- struct ablkcipher_request *req = ablkcipher_request_cast(async_req);
|
||||
- struct qce_cipher_reqctx *rctx = ablkcipher_request_ctx(req);
|
||||
- struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req);
|
||||
- struct qce_alg_template *tmpl = to_cipher_tmpl(async_req->tfm);
|
||||
- struct qce_device *qce = tmpl->qce;
|
||||
- enum dma_data_direction dir_src, dir_dst;
|
||||
- struct scatterlist *sg;
|
||||
- bool diff_dst;
|
||||
- gfp_t gfp;
|
||||
- int ret;
|
||||
-
|
||||
- rctx->iv = req->info;
|
||||
- rctx->ivsize = crypto_ablkcipher_ivsize(ablkcipher);
|
||||
- rctx->cryptlen = req->nbytes;
|
||||
-
|
||||
- diff_dst = (req->src != req->dst) ? true : false;
|
||||
- dir_src = diff_dst ? DMA_TO_DEVICE : DMA_BIDIRECTIONAL;
|
||||
- dir_dst = diff_dst ? DMA_FROM_DEVICE : DMA_BIDIRECTIONAL;
|
||||
-
|
||||
- rctx->src_nents = sg_nents_for_len(req->src, req->nbytes);
|
||||
- if (diff_dst)
|
||||
- rctx->dst_nents = sg_nents_for_len(req->dst, req->nbytes);
|
||||
- else
|
||||
- rctx->dst_nents = rctx->src_nents;
|
||||
- if (rctx->src_nents < 0) {
|
||||
- dev_err(qce->dev, "Invalid numbers of src SG.\n");
|
||||
- return rctx->src_nents;
|
||||
- }
|
||||
- if (rctx->dst_nents < 0) {
|
||||
- dev_err(qce->dev, "Invalid numbers of dst SG.\n");
|
||||
- return -rctx->dst_nents;
|
||||
- }
|
||||
-
|
||||
- rctx->dst_nents += 1;
|
||||
-
|
||||
- gfp = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
|
||||
- GFP_KERNEL : GFP_ATOMIC;
|
||||
-
|
||||
- ret = sg_alloc_table(&rctx->dst_tbl, rctx->dst_nents, gfp);
|
||||
- if (ret)
|
||||
- return ret;
|
||||
-
|
||||
- sg_init_one(&rctx->result_sg, qce->dma.result_buf, QCE_RESULT_BUF_SZ);
|
||||
-
|
||||
- sg = qce_sgtable_add(&rctx->dst_tbl, req->dst);
|
||||
- if (IS_ERR(sg)) {
|
||||
- ret = PTR_ERR(sg);
|
||||
- goto error_free;
|
||||
- }
|
||||
-
|
||||
- sg = qce_sgtable_add(&rctx->dst_tbl, &rctx->result_sg);
|
||||
- if (IS_ERR(sg)) {
|
||||
- ret = PTR_ERR(sg);
|
||||
- goto error_free;
|
||||
- }
|
||||
-
|
||||
- sg_mark_end(sg);
|
||||
- rctx->dst_sg = rctx->dst_tbl.sgl;
|
||||
-
|
||||
- ret = dma_map_sg(qce->dev, rctx->dst_sg, rctx->dst_nents, dir_dst);
|
||||
- if (ret < 0)
|
||||
- goto error_free;
|
||||
-
|
||||
- if (diff_dst) {
|
||||
- ret = dma_map_sg(qce->dev, req->src, rctx->src_nents, dir_src);
|
||||
- if (ret < 0)
|
||||
- goto error_unmap_dst;
|
||||
- rctx->src_sg = req->src;
|
||||
- } else {
|
||||
- rctx->src_sg = rctx->dst_sg;
|
||||
- }
|
||||
-
|
||||
- ret = qce_dma_prep_sgs(&qce->dma, rctx->src_sg, rctx->src_nents,
|
||||
- rctx->dst_sg, rctx->dst_nents,
|
||||
- qce_ablkcipher_done, async_req);
|
||||
- if (ret)
|
||||
- goto error_unmap_src;
|
||||
-
|
||||
- qce_dma_issue_pending(&qce->dma);
|
||||
-
|
||||
- ret = qce_start(async_req, tmpl->crypto_alg_type, req->nbytes, 0);
|
||||
- if (ret)
|
||||
- goto error_terminate;
|
||||
-
|
||||
- return 0;
|
||||
-
|
||||
-error_terminate:
|
||||
- qce_dma_terminate_all(&qce->dma);
|
||||
-error_unmap_src:
|
||||
- if (diff_dst)
|
||||
- dma_unmap_sg(qce->dev, req->src, rctx->src_nents, dir_src);
|
||||
-error_unmap_dst:
|
||||
- dma_unmap_sg(qce->dev, rctx->dst_sg, rctx->dst_nents, dir_dst);
|
||||
-error_free:
|
||||
- sg_free_table(&rctx->dst_tbl);
|
||||
- return ret;
|
||||
-}
|
||||
-
|
||||
-static int qce_ablkcipher_setkey(struct crypto_ablkcipher *ablk, const u8 *key,
|
||||
- unsigned int keylen)
|
||||
-{
|
||||
- struct crypto_tfm *tfm = crypto_ablkcipher_tfm(ablk);
|
||||
- struct qce_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
|
||||
- unsigned long flags = to_cipher_tmpl(tfm)->alg_flags;
|
||||
- int ret;
|
||||
-
|
||||
- if (!key || !keylen)
|
||||
- return -EINVAL;
|
||||
-
|
||||
- if (IS_AES(flags)) {
|
||||
- switch (keylen) {
|
||||
- case AES_KEYSIZE_128:
|
||||
- case AES_KEYSIZE_256:
|
||||
- break;
|
||||
- default:
|
||||
- goto fallback;
|
||||
- }
|
||||
- } else if (IS_DES(flags)) {
|
||||
- u32 tmp[DES_EXPKEY_WORDS];
|
||||
-
|
||||
- ret = des_ekey(tmp, key);
|
||||
- if (!ret && crypto_ablkcipher_get_flags(ablk) &
|
||||
- CRYPTO_TFM_REQ_WEAK_KEY)
|
||||
- goto weakkey;
|
||||
- }
|
||||
-
|
||||
- ctx->enc_keylen = keylen;
|
||||
- memcpy(ctx->enc_key, key, keylen);
|
||||
- return 0;
|
||||
-fallback:
|
||||
- ret = crypto_skcipher_setkey(ctx->fallback, key, keylen);
|
||||
- if (!ret)
|
||||
- ctx->enc_keylen = keylen;
|
||||
- return ret;
|
||||
-weakkey:
|
||||
- crypto_ablkcipher_set_flags(ablk, CRYPTO_TFM_RES_WEAK_KEY);
|
||||
- return -EINVAL;
|
||||
-}
|
||||
-
|
||||
-static int qce_ablkcipher_crypt(struct ablkcipher_request *req, int encrypt)
|
||||
-{
|
||||
- struct crypto_tfm *tfm =
|
||||
- crypto_ablkcipher_tfm(crypto_ablkcipher_reqtfm(req));
|
||||
- struct qce_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
|
||||
- struct qce_cipher_reqctx *rctx = ablkcipher_request_ctx(req);
|
||||
- struct qce_alg_template *tmpl = to_cipher_tmpl(tfm);
|
||||
- int ret;
|
||||
-
|
||||
- rctx->flags = tmpl->alg_flags;
|
||||
- rctx->flags |= encrypt ? QCE_ENCRYPT : QCE_DECRYPT;
|
||||
-
|
||||
- if (IS_AES(rctx->flags) && ctx->enc_keylen != AES_KEYSIZE_128 &&
|
||||
- ctx->enc_keylen != AES_KEYSIZE_256) {
|
||||
- SKCIPHER_REQUEST_ON_STACK(subreq, ctx->fallback);
|
||||
-
|
||||
- skcipher_request_set_tfm(subreq, ctx->fallback);
|
||||
- skcipher_request_set_callback(subreq, req->base.flags,
|
||||
- NULL, NULL);
|
||||
- skcipher_request_set_crypt(subreq, req->src, req->dst,
|
||||
- req->nbytes, req->info);
|
||||
- ret = encrypt ? crypto_skcipher_encrypt(subreq) :
|
||||
- crypto_skcipher_decrypt(subreq);
|
||||
- skcipher_request_zero(subreq);
|
||||
- return ret;
|
||||
- }
|
||||
-
|
||||
- return tmpl->qce->async_req_enqueue(tmpl->qce, &req->base);
|
||||
-}
|
||||
-
|
||||
-static int qce_ablkcipher_encrypt(struct ablkcipher_request *req)
|
||||
-{
|
||||
- return qce_ablkcipher_crypt(req, 1);
|
||||
-}
|
||||
-
|
||||
-static int qce_ablkcipher_decrypt(struct ablkcipher_request *req)
|
||||
-{
|
||||
- return qce_ablkcipher_crypt(req, 0);
|
||||
-}
|
||||
-
|
||||
-static int qce_ablkcipher_init(struct crypto_tfm *tfm)
|
||||
-{
|
||||
- struct qce_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
|
||||
-
|
||||
- memset(ctx, 0, sizeof(*ctx));
|
||||
- tfm->crt_ablkcipher.reqsize = sizeof(struct qce_cipher_reqctx);
|
||||
-
|
||||
- ctx->fallback = crypto_alloc_skcipher(crypto_tfm_alg_name(tfm), 0,
|
||||
- CRYPTO_ALG_ASYNC |
|
||||
- CRYPTO_ALG_NEED_FALLBACK);
|
||||
- if (IS_ERR(ctx->fallback))
|
||||
- return PTR_ERR(ctx->fallback);
|
||||
-
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
-static void qce_ablkcipher_exit(struct crypto_tfm *tfm)
|
||||
-{
|
||||
- struct qce_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
|
||||
-
|
||||
- crypto_free_skcipher(ctx->fallback);
|
||||
-}
|
||||
-
|
||||
-struct qce_ablkcipher_def {
|
||||
- unsigned long flags;
|
||||
- const char *name;
|
||||
- const char *drv_name;
|
||||
- unsigned int blocksize;
|
||||
- unsigned int ivsize;
|
||||
- unsigned int min_keysize;
|
||||
- unsigned int max_keysize;
|
||||
-};
|
||||
-
|
||||
-static const struct qce_ablkcipher_def ablkcipher_def[] = {
|
||||
- {
|
||||
- .flags = QCE_ALG_AES | QCE_MODE_ECB,
|
||||
- .name = "ecb(aes)",
|
||||
- .drv_name = "ecb-aes-qce",
|
||||
- .blocksize = AES_BLOCK_SIZE,
|
||||
- .ivsize = AES_BLOCK_SIZE,
|
||||
- .min_keysize = AES_MIN_KEY_SIZE,
|
||||
- .max_keysize = AES_MAX_KEY_SIZE,
|
||||
- },
|
||||
- {
|
||||
- .flags = QCE_ALG_AES | QCE_MODE_CBC,
|
||||
- .name = "cbc(aes)",
|
||||
- .drv_name = "cbc-aes-qce",
|
||||
- .blocksize = AES_BLOCK_SIZE,
|
||||
- .ivsize = AES_BLOCK_SIZE,
|
||||
- .min_keysize = AES_MIN_KEY_SIZE,
|
||||
- .max_keysize = AES_MAX_KEY_SIZE,
|
||||
- },
|
||||
- {
|
||||
- .flags = QCE_ALG_AES | QCE_MODE_CTR,
|
||||
- .name = "ctr(aes)",
|
||||
- .drv_name = "ctr-aes-qce",
|
||||
- .blocksize = AES_BLOCK_SIZE,
|
||||
- .ivsize = AES_BLOCK_SIZE,
|
||||
- .min_keysize = AES_MIN_KEY_SIZE,
|
||||
- .max_keysize = AES_MAX_KEY_SIZE,
|
||||
- },
|
||||
- {
|
||||
- .flags = QCE_ALG_AES | QCE_MODE_XTS,
|
||||
- .name = "xts(aes)",
|
||||
- .drv_name = "xts-aes-qce",
|
||||
- .blocksize = AES_BLOCK_SIZE,
|
||||
- .ivsize = AES_BLOCK_SIZE,
|
||||
- .min_keysize = AES_MIN_KEY_SIZE,
|
||||
- .max_keysize = AES_MAX_KEY_SIZE,
|
||||
- },
|
||||
- {
|
||||
- .flags = QCE_ALG_DES | QCE_MODE_ECB,
|
||||
- .name = "ecb(des)",
|
||||
- .drv_name = "ecb-des-qce",
|
||||
- .blocksize = DES_BLOCK_SIZE,
|
||||
- .ivsize = 0,
|
||||
- .min_keysize = DES_KEY_SIZE,
|
||||
- .max_keysize = DES_KEY_SIZE,
|
||||
- },
|
||||
- {
|
||||
- .flags = QCE_ALG_DES | QCE_MODE_CBC,
|
||||
- .name = "cbc(des)",
|
||||
- .drv_name = "cbc-des-qce",
|
||||
- .blocksize = DES_BLOCK_SIZE,
|
||||
- .ivsize = DES_BLOCK_SIZE,
|
||||
- .min_keysize = DES_KEY_SIZE,
|
||||
- .max_keysize = DES_KEY_SIZE,
|
||||
- },
|
||||
- {
|
||||
- .flags = QCE_ALG_3DES | QCE_MODE_ECB,
|
||||
- .name = "ecb(des3_ede)",
|
||||
- .drv_name = "ecb-3des-qce",
|
||||
- .blocksize = DES3_EDE_BLOCK_SIZE,
|
||||
- .ivsize = 0,
|
||||
- .min_keysize = DES3_EDE_KEY_SIZE,
|
||||
- .max_keysize = DES3_EDE_KEY_SIZE,
|
||||
- },
|
||||
- {
|
||||
- .flags = QCE_ALG_3DES | QCE_MODE_CBC,
|
||||
- .name = "cbc(des3_ede)",
|
||||
- .drv_name = "cbc-3des-qce",
|
||||
- .blocksize = DES3_EDE_BLOCK_SIZE,
|
||||
- .ivsize = DES3_EDE_BLOCK_SIZE,
|
||||
- .min_keysize = DES3_EDE_KEY_SIZE,
|
||||
- .max_keysize = DES3_EDE_KEY_SIZE,
|
||||
- },
|
||||
-};
|
||||
-
|
||||
-static int qce_ablkcipher_register_one(const struct qce_ablkcipher_def *def,
|
||||
- struct qce_device *qce)
|
||||
-{
|
||||
- struct qce_alg_template *tmpl;
|
||||
- struct crypto_alg *alg;
|
||||
- int ret;
|
||||
-
|
||||
- tmpl = kzalloc(sizeof(*tmpl), GFP_KERNEL);
|
||||
- if (!tmpl)
|
||||
- return -ENOMEM;
|
||||
-
|
||||
- alg = &tmpl->alg.crypto;
|
||||
-
|
||||
- snprintf(alg->cra_name, CRYPTO_MAX_ALG_NAME, "%s", def->name);
|
||||
- snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s",
|
||||
- def->drv_name);
|
||||
-
|
||||
- alg->cra_blocksize = def->blocksize;
|
||||
- alg->cra_ablkcipher.ivsize = def->ivsize;
|
||||
- alg->cra_ablkcipher.min_keysize = def->min_keysize;
|
||||
- alg->cra_ablkcipher.max_keysize = def->max_keysize;
|
||||
- alg->cra_ablkcipher.setkey = qce_ablkcipher_setkey;
|
||||
- alg->cra_ablkcipher.encrypt = qce_ablkcipher_encrypt;
|
||||
- alg->cra_ablkcipher.decrypt = qce_ablkcipher_decrypt;
|
||||
-
|
||||
- alg->cra_priority = 300;
|
||||
- alg->cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC |
|
||||
- CRYPTO_ALG_NEED_FALLBACK | CRYPTO_ALG_KERN_DRIVER_ONLY;
|
||||
- alg->cra_ctxsize = sizeof(struct qce_cipher_ctx);
|
||||
- alg->cra_alignmask = 0;
|
||||
- alg->cra_type = &crypto_ablkcipher_type;
|
||||
- alg->cra_module = THIS_MODULE;
|
||||
- alg->cra_init = qce_ablkcipher_init;
|
||||
- alg->cra_exit = qce_ablkcipher_exit;
|
||||
- INIT_LIST_HEAD(&alg->cra_list);
|
||||
-
|
||||
- INIT_LIST_HEAD(&tmpl->entry);
|
||||
- tmpl->crypto_alg_type = CRYPTO_ALG_TYPE_ABLKCIPHER;
|
||||
- tmpl->alg_flags = def->flags;
|
||||
- tmpl->qce = qce;
|
||||
-
|
||||
- ret = crypto_register_alg(alg);
|
||||
- if (ret) {
|
||||
- kfree(tmpl);
|
||||
- dev_err(qce->dev, "%s registration failed\n", alg->cra_name);
|
||||
- return ret;
|
||||
- }
|
||||
-
|
||||
- list_add_tail(&tmpl->entry, &ablkcipher_algs);
|
||||
- dev_dbg(qce->dev, "%s is registered\n", alg->cra_name);
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
-static void qce_ablkcipher_unregister(struct qce_device *qce)
|
||||
-{
|
||||
- struct qce_alg_template *tmpl, *n;
|
||||
-
|
||||
- list_for_each_entry_safe(tmpl, n, &ablkcipher_algs, entry) {
|
||||
- crypto_unregister_alg(&tmpl->alg.crypto);
|
||||
- list_del(&tmpl->entry);
|
||||
- kfree(tmpl);
|
||||
- }
|
||||
-}
|
||||
-
|
||||
-static int qce_ablkcipher_register(struct qce_device *qce)
|
||||
-{
|
||||
- int ret, i;
|
||||
-
|
||||
- for (i = 0; i < ARRAY_SIZE(ablkcipher_def); i++) {
|
||||
- ret = qce_ablkcipher_register_one(&ablkcipher_def[i], qce);
|
||||
- if (ret)
|
||||
- goto err;
|
||||
- }
|
||||
-
|
||||
- return 0;
|
||||
-err:
|
||||
- qce_ablkcipher_unregister(qce);
|
||||
- return ret;
|
||||
-}
|
||||
-
|
||||
-const struct qce_algo_ops ablkcipher_ops = {
|
||||
- .type = CRYPTO_ALG_TYPE_ABLKCIPHER,
|
||||
- .register_algs = qce_ablkcipher_register,
|
||||
- .unregister_algs = qce_ablkcipher_unregister,
|
||||
- .async_req_handle = qce_ablkcipher_async_req_handle,
|
||||
-};
|
||||
--- /dev/null
|
||||
+++ b/drivers/crypto/qce/skcipher.c
|
||||
@@ -0,0 +1,432 @@
|
||||
+/*
|
||||
+ * Copyright (c) 2010-2014, The Linux Foundation. All rights reserved.
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify
|
||||
+ * it under the terms of the GNU General Public License version 2 and
|
||||
+ * only version 2 as published by the Free Software Foundation.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful,
|
||||
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
+ * GNU General Public License for more details.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/device.h>
|
||||
+#include <linux/interrupt.h>
|
||||
+#include <linux/types.h>
|
||||
+#include <crypto/aes.h>
|
||||
+#include <crypto/des.h>
|
||||
+#include <crypto/internal/skcipher.h>
|
||||
+
|
||||
+#include "cipher.h"
|
||||
+
|
||||
+static LIST_HEAD(skcipher_algs);
|
||||
+
|
||||
+static void qce_skcipher_done(void *data)
|
||||
+{
|
||||
+ struct crypto_async_request *async_req = data;
|
||||
+ struct skcipher_request *req = skcipher_request_cast(async_req);
|
||||
+ struct qce_cipher_reqctx *rctx = skcipher_request_ctx(req);
|
||||
+ struct qce_alg_template *tmpl = to_cipher_tmpl(crypto_skcipher_reqtfm(req));
|
||||
+ struct qce_device *qce = tmpl->qce;
|
||||
+ enum dma_data_direction dir_src, dir_dst;
|
||||
+ u32 status;
|
||||
+ int error;
|
||||
+ bool diff_dst;
|
||||
+
|
||||
+ diff_dst = (req->src != req->dst) ? true : false;
|
||||
+ dir_src = diff_dst ? DMA_TO_DEVICE : DMA_BIDIRECTIONAL;
|
||||
+ dir_dst = diff_dst ? DMA_FROM_DEVICE : DMA_BIDIRECTIONAL;
|
||||
+
|
||||
+ error = qce_dma_terminate_all(&qce->dma);
|
||||
+ if (error)
|
||||
+ dev_dbg(qce->dev, "skcipher dma termination error (%d)\n",
|
||||
+ error);
|
||||
+
|
||||
+ if (diff_dst)
|
||||
+ dma_unmap_sg(qce->dev, rctx->src_sg, rctx->src_nents, dir_src);
|
||||
+ dma_unmap_sg(qce->dev, rctx->dst_sg, rctx->dst_nents, dir_dst);
|
||||
+
|
||||
+ sg_free_table(&rctx->dst_tbl);
|
||||
+
|
||||
+ error = qce_check_status(qce, &status);
|
||||
+ if (error < 0)
|
||||
+ dev_dbg(qce->dev, "skcipher operation error (%x)\n", status);
|
||||
+
|
||||
+ qce->async_req_done(tmpl->qce, error);
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+qce_skcipher_async_req_handle(struct crypto_async_request *async_req)
|
||||
+{
|
||||
+ struct skcipher_request *req = skcipher_request_cast(async_req);
|
||||
+ struct qce_cipher_reqctx *rctx = skcipher_request_ctx(req);
|
||||
+ struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
|
||||
+ struct qce_alg_template *tmpl = to_cipher_tmpl(crypto_skcipher_reqtfm(req));
|
||||
+ struct qce_device *qce = tmpl->qce;
|
||||
+ enum dma_data_direction dir_src, dir_dst;
|
||||
+ struct scatterlist *sg;
|
||||
+ bool diff_dst;
|
||||
+ gfp_t gfp;
|
||||
+ int ret;
|
||||
+
|
||||
+ rctx->iv = req->iv;
|
||||
+ rctx->ivsize = crypto_skcipher_ivsize(skcipher);
|
||||
+ rctx->cryptlen = req->cryptlen;
|
||||
+
|
||||
+ diff_dst = (req->src != req->dst) ? true : false;
|
||||
+ dir_src = diff_dst ? DMA_TO_DEVICE : DMA_BIDIRECTIONAL;
|
||||
+ dir_dst = diff_dst ? DMA_FROM_DEVICE : DMA_BIDIRECTIONAL;
|
||||
+
|
||||
+ rctx->src_nents = sg_nents_for_len(req->src, req->cryptlen);
|
||||
+ if (diff_dst)
|
||||
+ rctx->dst_nents = sg_nents_for_len(req->dst, req->cryptlen);
|
||||
+ else
|
||||
+ rctx->dst_nents = rctx->src_nents;
|
||||
+ if (rctx->src_nents < 0) {
|
||||
+ dev_err(qce->dev, "Invalid numbers of src SG.\n");
|
||||
+ return rctx->src_nents;
|
||||
+ }
|
||||
+ if (rctx->dst_nents < 0) {
|
||||
+ dev_err(qce->dev, "Invalid numbers of dst SG.\n");
|
||||
+ return -rctx->dst_nents;
|
||||
+ }
|
||||
+
|
||||
+ rctx->dst_nents += 1;
|
||||
+
|
||||
+ gfp = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
|
||||
+ GFP_KERNEL : GFP_ATOMIC;
|
||||
+
|
||||
+ ret = sg_alloc_table(&rctx->dst_tbl, rctx->dst_nents, gfp);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ sg_init_one(&rctx->result_sg, qce->dma.result_buf, QCE_RESULT_BUF_SZ);
|
||||
+
|
||||
+ sg = qce_sgtable_add(&rctx->dst_tbl, req->dst);
|
||||
+ if (IS_ERR(sg)) {
|
||||
+ ret = PTR_ERR(sg);
|
||||
+ goto error_free;
|
||||
+ }
|
||||
+
|
||||
+ sg = qce_sgtable_add(&rctx->dst_tbl, &rctx->result_sg);
|
||||
+ if (IS_ERR(sg)) {
|
||||
+ ret = PTR_ERR(sg);
|
||||
+ goto error_free;
|
||||
+ }
|
||||
+
|
||||
+ sg_mark_end(sg);
|
||||
+ rctx->dst_sg = rctx->dst_tbl.sgl;
|
||||
+
|
||||
+ ret = dma_map_sg(qce->dev, rctx->dst_sg, rctx->dst_nents, dir_dst);
|
||||
+ if (ret < 0)
|
||||
+ goto error_free;
|
||||
+
|
||||
+ if (diff_dst) {
|
||||
+ ret = dma_map_sg(qce->dev, req->src, rctx->src_nents, dir_src);
|
||||
+ if (ret < 0)
|
||||
+ goto error_unmap_dst;
|
||||
+ rctx->src_sg = req->src;
|
||||
+ } else {
|
||||
+ rctx->src_sg = rctx->dst_sg;
|
||||
+ }
|
||||
+
|
||||
+ ret = qce_dma_prep_sgs(&qce->dma, rctx->src_sg, rctx->src_nents,
|
||||
+ rctx->dst_sg, rctx->dst_nents,
|
||||
+ qce_skcipher_done, async_req);
|
||||
+ if (ret)
|
||||
+ goto error_unmap_src;
|
||||
+
|
||||
+ qce_dma_issue_pending(&qce->dma);
|
||||
+
|
||||
+ ret = qce_start(async_req, tmpl->crypto_alg_type, req->cryptlen, 0);
|
||||
+ if (ret)
|
||||
+ goto error_terminate;
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+error_terminate:
|
||||
+ qce_dma_terminate_all(&qce->dma);
|
||||
+error_unmap_src:
|
||||
+ if (diff_dst)
|
||||
+ dma_unmap_sg(qce->dev, req->src, rctx->src_nents, dir_src);
|
||||
+error_unmap_dst:
|
||||
+ dma_unmap_sg(qce->dev, rctx->dst_sg, rctx->dst_nents, dir_dst);
|
||||
+error_free:
|
||||
+ sg_free_table(&rctx->dst_tbl);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int qce_skcipher_setkey(struct crypto_skcipher *ablk, const u8 *key,
|
||||
+ unsigned int keylen)
|
||||
+{
|
||||
+ struct qce_cipher_ctx *ctx = crypto_skcipher_ctx(ablk);
|
||||
+ unsigned long flags = to_cipher_tmpl(ablk)->alg_flags;
|
||||
+ int ret;
|
||||
+
|
||||
+ if (!key || !keylen)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (IS_AES(flags)) {
|
||||
+ switch (keylen) {
|
||||
+ case AES_KEYSIZE_128:
|
||||
+ case AES_KEYSIZE_256:
|
||||
+ break;
|
||||
+ default:
|
||||
+ goto fallback;
|
||||
+ }
|
||||
+ } else if (IS_DES(flags)) {
|
||||
+ u32 tmp[DES_EXPKEY_WORDS];
|
||||
+
|
||||
+ ret = des_ekey(tmp, key);
|
||||
+ if (!ret && crypto_skcipher_get_flags(ablk) &
|
||||
+ CRYPTO_TFM_REQ_WEAK_KEY)
|
||||
+ goto weakkey;
|
||||
+ }
|
||||
+
|
||||
+ ctx->enc_keylen = keylen;
|
||||
+ memcpy(ctx->enc_key, key, keylen);
|
||||
+ return 0;
|
||||
+fallback:
|
||||
+ ret = crypto_skcipher_setkey(ctx->fallback, key, keylen);
|
||||
+ if (!ret)
|
||||
+ ctx->enc_keylen = keylen;
|
||||
+ return ret;
|
||||
+weakkey:
|
||||
+ crypto_skcipher_set_flags(ablk, CRYPTO_TFM_RES_WEAK_KEY);
|
||||
+ return -EINVAL;
|
||||
+}
|
||||
+
|
||||
+static int qce_skcipher_crypt(struct skcipher_request *req, int encrypt)
|
||||
+{
|
||||
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
|
||||
+ struct qce_cipher_ctx *ctx = crypto_skcipher_ctx(tfm);
|
||||
+ struct qce_cipher_reqctx *rctx = skcipher_request_ctx(req);
|
||||
+ struct qce_alg_template *tmpl = to_cipher_tmpl(tfm);
|
||||
+ int ret;
|
||||
+
|
||||
+ rctx->flags = tmpl->alg_flags;
|
||||
+ rctx->flags |= encrypt ? QCE_ENCRYPT : QCE_DECRYPT;
|
||||
+
|
||||
+ if (IS_AES(rctx->flags) && ctx->enc_keylen != AES_KEYSIZE_128 &&
|
||||
+ ctx->enc_keylen != AES_KEYSIZE_256) {
|
||||
+ SKCIPHER_REQUEST_ON_STACK(subreq, ctx->fallback);
|
||||
+
|
||||
+ skcipher_request_set_tfm(subreq, ctx->fallback);
|
||||
+ skcipher_request_set_callback(subreq, req->base.flags,
|
||||
+ NULL, NULL);
|
||||
+ skcipher_request_set_crypt(subreq, req->src, req->dst,
|
||||
+ req->cryptlen, req->iv);
|
||||
+ ret = encrypt ? crypto_skcipher_encrypt(subreq) :
|
||||
+ crypto_skcipher_decrypt(subreq);
|
||||
+ skcipher_request_zero(subreq);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ return tmpl->qce->async_req_enqueue(tmpl->qce, &req->base);
|
||||
+}
|
||||
+
|
||||
+static int qce_skcipher_encrypt(struct skcipher_request *req)
|
||||
+{
|
||||
+ return qce_skcipher_crypt(req, 1);
|
||||
+}
|
||||
+
|
||||
+static int qce_skcipher_decrypt(struct skcipher_request *req)
|
||||
+{
|
||||
+ return qce_skcipher_crypt(req, 0);
|
||||
+}
|
||||
+
|
||||
+static int qce_skcipher_init(struct crypto_skcipher *tfm)
|
||||
+{
|
||||
+ struct qce_cipher_ctx *ctx = crypto_skcipher_ctx(tfm);
|
||||
+
|
||||
+ memset(ctx, 0, sizeof(*ctx));
|
||||
+ crypto_skcipher_set_reqsize(tfm, sizeof(struct qce_cipher_reqctx));
|
||||
+
|
||||
+ ctx->fallback = crypto_alloc_skcipher(crypto_tfm_alg_name(&tfm->base),
|
||||
+ 0, CRYPTO_ALG_ASYNC |
|
||||
+ CRYPTO_ALG_NEED_FALLBACK);
|
||||
+ if (IS_ERR(ctx->fallback))
|
||||
+ return PTR_ERR(ctx->fallback);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void qce_skcipher_exit(struct crypto_skcipher *tfm)
|
||||
+{
|
||||
+ struct qce_cipher_ctx *ctx = crypto_skcipher_ctx(tfm);
|
||||
+
|
||||
+ crypto_free_skcipher(ctx->fallback);
|
||||
+}
|
||||
+
|
||||
+struct qce_skcipher_def {
|
||||
+ unsigned long flags;
|
||||
+ const char *name;
|
||||
+ const char *drv_name;
|
||||
+ unsigned int blocksize;
|
||||
+ unsigned int ivsize;
|
||||
+ unsigned int min_keysize;
|
||||
+ unsigned int max_keysize;
|
||||
+};
|
||||
+
|
||||
+static const struct qce_skcipher_def skcipher_def[] = {
|
||||
+ {
|
||||
+ .flags = QCE_ALG_AES | QCE_MODE_ECB,
|
||||
+ .name = "ecb(aes)",
|
||||
+ .drv_name = "ecb-aes-qce",
|
||||
+ .blocksize = AES_BLOCK_SIZE,
|
||||
+ .ivsize = AES_BLOCK_SIZE,
|
||||
+ .min_keysize = AES_MIN_KEY_SIZE,
|
||||
+ .max_keysize = AES_MAX_KEY_SIZE,
|
||||
+ },
|
||||
+ {
|
||||
+ .flags = QCE_ALG_AES | QCE_MODE_CBC,
|
||||
+ .name = "cbc(aes)",
|
||||
+ .drv_name = "cbc-aes-qce",
|
||||
+ .blocksize = AES_BLOCK_SIZE,
|
||||
+ .ivsize = AES_BLOCK_SIZE,
|
||||
+ .min_keysize = AES_MIN_KEY_SIZE,
|
||||
+ .max_keysize = AES_MAX_KEY_SIZE,
|
||||
+ },
|
||||
+ {
|
||||
+ .flags = QCE_ALG_AES | QCE_MODE_CTR,
|
||||
+ .name = "ctr(aes)",
|
||||
+ .drv_name = "ctr-aes-qce",
|
||||
+ .blocksize = AES_BLOCK_SIZE,
|
||||
+ .ivsize = AES_BLOCK_SIZE,
|
||||
+ .min_keysize = AES_MIN_KEY_SIZE,
|
||||
+ .max_keysize = AES_MAX_KEY_SIZE,
|
||||
+ },
|
||||
+ {
|
||||
+ .flags = QCE_ALG_AES | QCE_MODE_XTS,
|
||||
+ .name = "xts(aes)",
|
||||
+ .drv_name = "xts-aes-qce",
|
||||
+ .blocksize = AES_BLOCK_SIZE,
|
||||
+ .ivsize = AES_BLOCK_SIZE,
|
||||
+ .min_keysize = AES_MIN_KEY_SIZE,
|
||||
+ .max_keysize = AES_MAX_KEY_SIZE,
|
||||
+ },
|
||||
+ {
|
||||
+ .flags = QCE_ALG_DES | QCE_MODE_ECB,
|
||||
+ .name = "ecb(des)",
|
||||
+ .drv_name = "ecb-des-qce",
|
||||
+ .blocksize = DES_BLOCK_SIZE,
|
||||
+ .ivsize = 0,
|
||||
+ .min_keysize = DES_KEY_SIZE,
|
||||
+ .max_keysize = DES_KEY_SIZE,
|
||||
+ },
|
||||
+ {
|
||||
+ .flags = QCE_ALG_DES | QCE_MODE_CBC,
|
||||
+ .name = "cbc(des)",
|
||||
+ .drv_name = "cbc-des-qce",
|
||||
+ .blocksize = DES_BLOCK_SIZE,
|
||||
+ .ivsize = DES_BLOCK_SIZE,
|
||||
+ .min_keysize = DES_KEY_SIZE,
|
||||
+ .max_keysize = DES_KEY_SIZE,
|
||||
+ },
|
||||
+ {
|
||||
+ .flags = QCE_ALG_3DES | QCE_MODE_ECB,
|
||||
+ .name = "ecb(des3_ede)",
|
||||
+ .drv_name = "ecb-3des-qce",
|
||||
+ .blocksize = DES3_EDE_BLOCK_SIZE,
|
||||
+ .ivsize = 0,
|
||||
+ .min_keysize = DES3_EDE_KEY_SIZE,
|
||||
+ .max_keysize = DES3_EDE_KEY_SIZE,
|
||||
+ },
|
||||
+ {
|
||||
+ .flags = QCE_ALG_3DES | QCE_MODE_CBC,
|
||||
+ .name = "cbc(des3_ede)",
|
||||
+ .drv_name = "cbc-3des-qce",
|
||||
+ .blocksize = DES3_EDE_BLOCK_SIZE,
|
||||
+ .ivsize = DES3_EDE_BLOCK_SIZE,
|
||||
+ .min_keysize = DES3_EDE_KEY_SIZE,
|
||||
+ .max_keysize = DES3_EDE_KEY_SIZE,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+static int qce_skcipher_register_one(const struct qce_skcipher_def *def,
|
||||
+ struct qce_device *qce)
|
||||
+{
|
||||
+ struct qce_alg_template *tmpl;
|
||||
+ struct skcipher_alg *alg;
|
||||
+ int ret;
|
||||
+
|
||||
+ tmpl = kzalloc(sizeof(*tmpl), GFP_KERNEL);
|
||||
+ if (!tmpl)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ alg = &tmpl->alg.skcipher;
|
||||
+
|
||||
+ snprintf(alg->base.cra_name, CRYPTO_MAX_ALG_NAME, "%s", def->name);
|
||||
+ snprintf(alg->base.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s",
|
||||
+ def->drv_name);
|
||||
+
|
||||
+ alg->base.cra_blocksize = def->blocksize;
|
||||
+ alg->ivsize = def->ivsize;
|
||||
+ alg->min_keysize = def->min_keysize;
|
||||
+ alg->max_keysize = def->max_keysize;
|
||||
+ alg->setkey = qce_skcipher_setkey;
|
||||
+ alg->encrypt = qce_skcipher_encrypt;
|
||||
+ alg->decrypt = qce_skcipher_decrypt;
|
||||
+
|
||||
+ alg->base.cra_priority = 300;
|
||||
+ alg->base.cra_flags = CRYPTO_ALG_ASYNC |
|
||||
+ CRYPTO_ALG_NEED_FALLBACK |
|
||||
+ CRYPTO_ALG_KERN_DRIVER_ONLY;
|
||||
+ alg->base.cra_ctxsize = sizeof(struct qce_cipher_ctx);
|
||||
+ alg->base.cra_alignmask = 0;
|
||||
+ alg->base.cra_module = THIS_MODULE;
|
||||
+
|
||||
+ alg->init = qce_skcipher_init;
|
||||
+ alg->exit = qce_skcipher_exit;
|
||||
+
|
||||
+ INIT_LIST_HEAD(&tmpl->entry);
|
||||
+ tmpl->crypto_alg_type = CRYPTO_ALG_TYPE_SKCIPHER;
|
||||
+ tmpl->alg_flags = def->flags;
|
||||
+ tmpl->qce = qce;
|
||||
+
|
||||
+ ret = crypto_register_skcipher(alg);
|
||||
+ if (ret) {
|
||||
+ kfree(tmpl);
|
||||
+ dev_err(qce->dev, "%s registration failed\n", alg->base.cra_name);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ list_add_tail(&tmpl->entry, &skcipher_algs);
|
||||
+ dev_dbg(qce->dev, "%s is registered\n", alg->base.cra_name);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void qce_skcipher_unregister(struct qce_device *qce)
|
||||
+{
|
||||
+ struct qce_alg_template *tmpl, *n;
|
||||
+
|
||||
+ list_for_each_entry_safe(tmpl, n, &skcipher_algs, entry) {
|
||||
+ crypto_unregister_skcipher(&tmpl->alg.skcipher);
|
||||
+ list_del(&tmpl->entry);
|
||||
+ kfree(tmpl);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static int qce_skcipher_register(struct qce_device *qce)
|
||||
+{
|
||||
+ int ret, i;
|
||||
+
|
||||
+ for (i = 0; i < ARRAY_SIZE(skcipher_def); i++) {
|
||||
+ ret = qce_skcipher_register_one(&skcipher_def[i], qce);
|
||||
+ if (ret)
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+err:
|
||||
+ qce_skcipher_unregister(qce);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+const struct qce_algo_ops skcipher_ops = {
|
||||
+ .type = CRYPTO_ALG_TYPE_SKCIPHER,
|
||||
+ .register_algs = qce_skcipher_register,
|
||||
+ .unregister_algs = qce_skcipher_unregister,
|
||||
+ .async_req_handle = qce_skcipher_async_req_handle,
|
||||
+};
|
||||
@ -1,39 +0,0 @@
|
||||
From 3f5598286445f695bb63a22239dd3603c69a6eaf Mon Sep 17 00:00:00 2001
|
||||
From: Eneas U de Queiroz <cotequeiroz@gmail.com>
|
||||
Date: Mon, 28 Oct 2019 09:03:07 -0300
|
||||
Subject: [PATCH] crypto: qce - fix ctr-aes-qce block, chunk sizes
|
||||
|
||||
Set blocksize of ctr-aes-qce to 1, so it can operate as a stream cipher,
|
||||
adding the definition for chucksize instead, where the underlying block
|
||||
size belongs.
|
||||
|
||||
Signed-off-by: Eneas U de Queiroz <cotequeiroz@gmail.com>
|
||||
|
||||
--- a/drivers/crypto/qce/skcipher.c
|
||||
+++ b/drivers/crypto/qce/skcipher.c
|
||||
@@ -264,6 +264,7 @@ struct qce_skcipher_def {
|
||||
const char *name;
|
||||
const char *drv_name;
|
||||
unsigned int blocksize;
|
||||
+ unsigned int chunksize;
|
||||
unsigned int ivsize;
|
||||
unsigned int min_keysize;
|
||||
unsigned int max_keysize;
|
||||
@@ -292,7 +293,8 @@ static const struct qce_skcipher_def skc
|
||||
.flags = QCE_ALG_AES | QCE_MODE_CTR,
|
||||
.name = "ctr(aes)",
|
||||
.drv_name = "ctr-aes-qce",
|
||||
- .blocksize = AES_BLOCK_SIZE,
|
||||
+ .blocksize = 1,
|
||||
+ .chunksize = AES_BLOCK_SIZE,
|
||||
.ivsize = AES_BLOCK_SIZE,
|
||||
.min_keysize = AES_MIN_KEY_SIZE,
|
||||
.max_keysize = AES_MAX_KEY_SIZE,
|
||||
@@ -362,6 +364,7 @@ static int qce_skcipher_register_one(con
|
||||
def->drv_name);
|
||||
|
||||
alg->base.cra_blocksize = def->blocksize;
|
||||
+ alg->chunksize = def->chunksize;
|
||||
alg->ivsize = def->ivsize;
|
||||
alg->min_keysize = def->min_keysize;
|
||||
alg->max_keysize = def->max_keysize;
|
||||
@ -1,50 +0,0 @@
|
||||
From 0138c3c13809250338d7cfba6f4ca3b2da02b2c8 Mon Sep 17 00:00:00 2001
|
||||
From: Eneas U de Queiroz <cotequeiroz@gmail.com>
|
||||
Date: Thu, 21 Nov 2019 14:28:23 -0300
|
||||
Subject: [PATCH] crypto: qce - fix xts-aes-qce key sizes
|
||||
|
||||
XTS-mode uses two keys, so the keysizes should be doubled in
|
||||
skcipher_def, and halved when checking if it is AES-128/192/256.
|
||||
|
||||
Signed-off-by: Eneas U de Queiroz <cotequeiroz@gmail.com>
|
||||
|
||||
--- a/drivers/crypto/qce/skcipher.c
|
||||
+++ b/drivers/crypto/qce/skcipher.c
|
||||
@@ -168,7 +168,7 @@ static int qce_skcipher_setkey(struct cr
|
||||
return -EINVAL;
|
||||
|
||||
if (IS_AES(flags)) {
|
||||
- switch (keylen) {
|
||||
+ switch (IS_XTS(flags) ? keylen >> 1 : keylen) {
|
||||
case AES_KEYSIZE_128:
|
||||
case AES_KEYSIZE_256:
|
||||
break;
|
||||
@@ -203,13 +203,15 @@ static int qce_skcipher_crypt(struct skc
|
||||
struct qce_cipher_ctx *ctx = crypto_skcipher_ctx(tfm);
|
||||
struct qce_cipher_reqctx *rctx = skcipher_request_ctx(req);
|
||||
struct qce_alg_template *tmpl = to_cipher_tmpl(tfm);
|
||||
+ int keylen;
|
||||
int ret;
|
||||
|
||||
rctx->flags = tmpl->alg_flags;
|
||||
rctx->flags |= encrypt ? QCE_ENCRYPT : QCE_DECRYPT;
|
||||
+ keylen = IS_XTS(rctx->flags) ? ctx->enc_keylen >> 1 : ctx->enc_keylen;
|
||||
|
||||
- if (IS_AES(rctx->flags) && ctx->enc_keylen != AES_KEYSIZE_128 &&
|
||||
- ctx->enc_keylen != AES_KEYSIZE_256) {
|
||||
+ if (IS_AES(rctx->flags) && keylen != AES_KEYSIZE_128 &&
|
||||
+ keylen != AES_KEYSIZE_256) {
|
||||
SKCIPHER_REQUEST_ON_STACK(subreq, ctx->fallback);
|
||||
|
||||
skcipher_request_set_tfm(subreq, ctx->fallback);
|
||||
@@ -305,8 +307,8 @@ static const struct qce_skcipher_def skc
|
||||
.drv_name = "xts-aes-qce",
|
||||
.blocksize = AES_BLOCK_SIZE,
|
||||
.ivsize = AES_BLOCK_SIZE,
|
||||
- .min_keysize = AES_MIN_KEY_SIZE,
|
||||
- .max_keysize = AES_MAX_KEY_SIZE,
|
||||
+ .min_keysize = AES_MIN_KEY_SIZE * 2,
|
||||
+ .max_keysize = AES_MAX_KEY_SIZE * 2,
|
||||
},
|
||||
{
|
||||
.flags = QCE_ALG_DES | QCE_MODE_ECB,
|
||||
@ -1,79 +0,0 @@
|
||||
From 31f796293b6c38126a466414c565827b9cfdbe39 Mon Sep 17 00:00:00 2001
|
||||
From: Eneas U de Queiroz <cotequeiroz@gmail.com>
|
||||
Date: Wed, 20 Nov 2019 21:39:11 -0300
|
||||
Subject: [PATCH] crypto: qce - save a sg table slot for result buf
|
||||
|
||||
When ctr-aes-qce is used for gcm-mode, an extra sg entry for the
|
||||
authentication tag is present, causing trouble when the qce driver
|
||||
prepares the dst-results eg table for dma.
|
||||
|
||||
It computes the number of entries needed with sg_nents_for_len, leaving
|
||||
out the tag entry. Then it creates a sg table with that number plus
|
||||
one, used to store a "result" sg.
|
||||
|
||||
When copying the sg table, it does not limit the number of entries
|
||||
copied, so tha extra slot is filled with the authentication tag sg.
|
||||
When the driver tries to add the result sg, the list is full, and it
|
||||
returns EINVAL.
|
||||
|
||||
By limiting the number of sg entries copied to the dest table, the slot
|
||||
for the result buffer is guaranteed to be unused.
|
||||
|
||||
Signed-off-by: Eneas U de Queiroz <cotequeiroz@gmail.com>
|
||||
|
||||
--- a/drivers/crypto/qce/dma.c
|
||||
+++ b/drivers/crypto/qce/dma.c
|
||||
@@ -55,7 +55,8 @@ void qce_dma_release(struct qce_dma_data
|
||||
}
|
||||
|
||||
struct scatterlist *
|
||||
-qce_sgtable_add(struct sg_table *sgt, struct scatterlist *new_sgl)
|
||||
+qce_sgtable_add(struct sg_table *sgt, struct scatterlist *new_sgl,
|
||||
+ int max_ents)
|
||||
{
|
||||
struct scatterlist *sg = sgt->sgl, *sg_last = NULL;
|
||||
|
||||
@@ -68,12 +69,13 @@ qce_sgtable_add(struct sg_table *sgt, st
|
||||
if (!sg)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
- while (new_sgl && sg) {
|
||||
+ while (new_sgl && sg && max_ents) {
|
||||
sg_set_page(sg, sg_page(new_sgl), new_sgl->length,
|
||||
new_sgl->offset);
|
||||
sg_last = sg;
|
||||
sg = sg_next(sg);
|
||||
new_sgl = sg_next(new_sgl);
|
||||
+ max_ents--;
|
||||
}
|
||||
|
||||
return sg_last;
|
||||
--- a/drivers/crypto/qce/dma.h
|
||||
+++ b/drivers/crypto/qce/dma.h
|
||||
@@ -50,6 +50,7 @@ int qce_dma_prep_sgs(struct qce_dma_data
|
||||
void qce_dma_issue_pending(struct qce_dma_data *dma);
|
||||
int qce_dma_terminate_all(struct qce_dma_data *dma);
|
||||
struct scatterlist *
|
||||
-qce_sgtable_add(struct sg_table *sgt, struct scatterlist *sg_add);
|
||||
+qce_sgtable_add(struct sg_table *sgt, struct scatterlist *sg_add,
|
||||
+ int max_ents);
|
||||
|
||||
#endif /* _DMA_H_ */
|
||||
--- a/drivers/crypto/qce/skcipher.c
|
||||
+++ b/drivers/crypto/qce/skcipher.c
|
||||
@@ -103,13 +103,13 @@ qce_skcipher_async_req_handle(struct cry
|
||||
|
||||
sg_init_one(&rctx->result_sg, qce->dma.result_buf, QCE_RESULT_BUF_SZ);
|
||||
|
||||
- sg = qce_sgtable_add(&rctx->dst_tbl, req->dst);
|
||||
+ sg = qce_sgtable_add(&rctx->dst_tbl, req->dst, rctx->dst_nents - 1);
|
||||
if (IS_ERR(sg)) {
|
||||
ret = PTR_ERR(sg);
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
- sg = qce_sgtable_add(&rctx->dst_tbl, &rctx->result_sg);
|
||||
+ sg = qce_sgtable_add(&rctx->dst_tbl, &rctx->result_sg, 1);
|
||||
if (IS_ERR(sg)) {
|
||||
ret = PTR_ERR(sg);
|
||||
goto error_free;
|
||||
@ -1,27 +0,0 @@
|
||||
From 502ca0b7c1d856a46dbd78e67690c12c47775b97 Mon Sep 17 00:00:00 2001
|
||||
From: Eneas U de Queiroz <cotequeiroz@gmail.com>
|
||||
Date: Fri, 22 Nov 2019 09:00:02 -0300
|
||||
Subject: [PATCH] crypto: qce - update the skcipher IV
|
||||
|
||||
Update the IV after the completion of each cipher operation.
|
||||
|
||||
Signed-off-by: Eneas U de Queiroz <cotequeiroz@gmail.com>
|
||||
|
||||
--- a/drivers/crypto/qce/skcipher.c
|
||||
+++ b/drivers/crypto/qce/skcipher.c
|
||||
@@ -29,6 +29,7 @@ static void qce_skcipher_done(void *data
|
||||
struct qce_cipher_reqctx *rctx = skcipher_request_ctx(req);
|
||||
struct qce_alg_template *tmpl = to_cipher_tmpl(crypto_skcipher_reqtfm(req));
|
||||
struct qce_device *qce = tmpl->qce;
|
||||
+ struct qce_result_dump *result_buf = qce->dma.result_buf;
|
||||
enum dma_data_direction dir_src, dir_dst;
|
||||
u32 status;
|
||||
int error;
|
||||
@@ -53,6 +54,7 @@ static void qce_skcipher_done(void *data
|
||||
if (error < 0)
|
||||
dev_dbg(qce->dev, "skcipher operation error (%x)\n", status);
|
||||
|
||||
+ memcpy(rctx->iv, result_buf->encr_cntr_iv, rctx->ivsize);
|
||||
qce->async_req_done(tmpl->qce, error);
|
||||
}
|
||||
|
||||
@ -1,54 +0,0 @@
|
||||
From f2a33ce18232919d3831d1c61a06b6067209282d Mon Sep 17 00:00:00 2001
|
||||
From: Eneas U de Queiroz <cotequeiroz@gmail.com>
|
||||
Date: Fri, 22 Nov 2019 09:34:29 -0300
|
||||
Subject: [PATCH] crypto: qce - initialize fallback only for AES
|
||||
|
||||
Adjust cra_flags to add CRYPTO_NEED_FALLBACK only for AES ciphers, where
|
||||
AES-192 is not handled by the qce hardware, and don't allocate & free
|
||||
the fallback skcipher for anything other than AES.
|
||||
|
||||
The rest of the code is unchanged, as the use of the fallback is already
|
||||
restricted to AES.
|
||||
|
||||
Signed-off-by: Eneas U de Queiroz <cotequeiroz@gmail.com>
|
||||
|
||||
--- a/drivers/crypto/qce/skcipher.c
|
||||
+++ b/drivers/crypto/qce/skcipher.c
|
||||
@@ -246,7 +246,15 @@ static int qce_skcipher_init(struct cryp
|
||||
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
crypto_skcipher_set_reqsize(tfm, sizeof(struct qce_cipher_reqctx));
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int qce_skcipher_init_fallback(struct crypto_skcipher *tfm)
|
||||
+{
|
||||
+ struct qce_cipher_ctx *ctx = crypto_skcipher_ctx(tfm);
|
||||
+ int ret;
|
||||
|
||||
+ qce_skcipher_init(tfm);
|
||||
ctx->fallback = crypto_alloc_skcipher(crypto_tfm_alg_name(&tfm->base),
|
||||
0, CRYPTO_ALG_ASYNC |
|
||||
CRYPTO_ALG_NEED_FALLBACK);
|
||||
@@ -378,14 +386,18 @@ static int qce_skcipher_register_one(con
|
||||
|
||||
alg->base.cra_priority = 300;
|
||||
alg->base.cra_flags = CRYPTO_ALG_ASYNC |
|
||||
- CRYPTO_ALG_NEED_FALLBACK |
|
||||
CRYPTO_ALG_KERN_DRIVER_ONLY;
|
||||
alg->base.cra_ctxsize = sizeof(struct qce_cipher_ctx);
|
||||
alg->base.cra_alignmask = 0;
|
||||
alg->base.cra_module = THIS_MODULE;
|
||||
|
||||
- alg->init = qce_skcipher_init;
|
||||
- alg->exit = qce_skcipher_exit;
|
||||
+ if (IS_AES(def->flags)) {
|
||||
+ alg->base.cra_flags |= CRYPTO_ALG_NEED_FALLBACK;
|
||||
+ alg->init = qce_skcipher_init_fallback;
|
||||
+ alg->exit = qce_skcipher_exit;
|
||||
+ } else {
|
||||
+ alg->init = qce_skcipher_init;
|
||||
+ }
|
||||
|
||||
INIT_LIST_HEAD(&tmpl->entry);
|
||||
tmpl->crypto_alg_type = CRYPTO_ALG_TYPE_SKCIPHER;
|
||||
@ -1,83 +0,0 @@
|
||||
From 686aa4db696270dadc5e8b2971769e1676251ff1 Mon Sep 17 00:00:00 2001
|
||||
From: Eneas U de Queiroz <cotequeiroz@gmail.com>
|
||||
Date: Fri, 31 Jan 2020 17:43:16 -0300
|
||||
Subject: [PATCH] crypto: qce - use cryptlen when adding extra sgl
|
||||
|
||||
The qce crypto driver appends an extra entry to the dst sgl, to maintain
|
||||
private state information.
|
||||
|
||||
When the gcm driver sends requests to the ctr skcipher, it passes the
|
||||
authentication tag after the actual crypto payload, but it must not be
|
||||
touched.
|
||||
|
||||
Commit 1336c2221bee ("crypto: qce - save a sg table slot for result
|
||||
buf") limited the destination sgl to avoid overwriting the
|
||||
authentication tag but it assumed the tag would be in a separate sgl
|
||||
entry.
|
||||
|
||||
This is not always the case, so it is better to limit the length of the
|
||||
destination buffer to req->cryptlen before appending the result buf.
|
||||
|
||||
Signed-off-by: Eneas U de Queiroz <cotequeiroz@gmail.com>
|
||||
|
||||
--- a/drivers/crypto/qce/dma.c
|
||||
+++ b/drivers/crypto/qce/dma.c
|
||||
@@ -56,9 +56,10 @@ void qce_dma_release(struct qce_dma_data
|
||||
|
||||
struct scatterlist *
|
||||
qce_sgtable_add(struct sg_table *sgt, struct scatterlist *new_sgl,
|
||||
- int max_ents)
|
||||
+ unsigned int max_len)
|
||||
{
|
||||
struct scatterlist *sg = sgt->sgl, *sg_last = NULL;
|
||||
+ unsigned int new_len;
|
||||
|
||||
while (sg) {
|
||||
if (!sg_page(sg))
|
||||
@@ -69,13 +70,13 @@ qce_sgtable_add(struct sg_table *sgt, st
|
||||
if (!sg)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
- while (new_sgl && sg && max_ents) {
|
||||
- sg_set_page(sg, sg_page(new_sgl), new_sgl->length,
|
||||
- new_sgl->offset);
|
||||
+ while (new_sgl && sg && max_len) {
|
||||
+ new_len = new_sgl->length > max_len ? max_len : new_sgl->length;
|
||||
+ sg_set_page(sg, sg_page(new_sgl), new_len, new_sgl->offset);
|
||||
sg_last = sg;
|
||||
sg = sg_next(sg);
|
||||
new_sgl = sg_next(new_sgl);
|
||||
- max_ents--;
|
||||
+ max_len -= new_len;
|
||||
}
|
||||
|
||||
return sg_last;
|
||||
--- a/drivers/crypto/qce/dma.h
|
||||
+++ b/drivers/crypto/qce/dma.h
|
||||
@@ -51,6 +51,6 @@ void qce_dma_issue_pending(struct qce_dm
|
||||
int qce_dma_terminate_all(struct qce_dma_data *dma);
|
||||
struct scatterlist *
|
||||
qce_sgtable_add(struct sg_table *sgt, struct scatterlist *sg_add,
|
||||
- int max_ents);
|
||||
+ unsigned int max_len);
|
||||
|
||||
#endif /* _DMA_H_ */
|
||||
--- a/drivers/crypto/qce/skcipher.c
|
||||
+++ b/drivers/crypto/qce/skcipher.c
|
||||
@@ -105,13 +105,14 @@ qce_skcipher_async_req_handle(struct cry
|
||||
|
||||
sg_init_one(&rctx->result_sg, qce->dma.result_buf, QCE_RESULT_BUF_SZ);
|
||||
|
||||
- sg = qce_sgtable_add(&rctx->dst_tbl, req->dst, rctx->dst_nents - 1);
|
||||
+ sg = qce_sgtable_add(&rctx->dst_tbl, req->dst, req->cryptlen);
|
||||
if (IS_ERR(sg)) {
|
||||
ret = PTR_ERR(sg);
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
- sg = qce_sgtable_add(&rctx->dst_tbl, &rctx->result_sg, 1);
|
||||
+ sg = qce_sgtable_add(&rctx->dst_tbl, &rctx->result_sg,
|
||||
+ QCE_RESULT_BUF_SZ);
|
||||
if (IS_ERR(sg)) {
|
||||
ret = PTR_ERR(sg);
|
||||
goto error_free;
|
||||
@ -1,122 +0,0 @@
|
||||
From 2d3b6fae7d1a2ad821769440daa91d7eec5c8250 Mon Sep 17 00:00:00 2001
|
||||
From: Eneas U de Queiroz <cotequeiroz@gmail.com>
|
||||
Date: Fri, 20 Dec 2019 09:41:44 -0300
|
||||
Subject: [PATCH] crypto: qce - use AES fallback for small requests
|
||||
|
||||
Process small blocks using the fallback cipher, as a workaround for an
|
||||
observed failure (DMA-related, apparently) when computing the GCM ghash
|
||||
key. This brings a speed gain as well, since it avoids the latency of
|
||||
using the hardware engine to process small blocks.
|
||||
|
||||
Using software for all 16-byte requests would be enough to make GCM
|
||||
work, but to increase performance, a larger threshold would be better.
|
||||
Measuring the performance of supported ciphers with openssl speed,
|
||||
software matches hardware at around 768-1024 bytes.
|
||||
|
||||
Considering the 256-bit ciphers, software is 2-3 times faster than qce
|
||||
at 256-bytes, 30% faster at 512, and about even at 768-bytes. With
|
||||
128-bit keys, the break-even point would be around 1024-bytes.
|
||||
|
||||
This adds the 'aes_sw_max_len' parameter, to set the largest request
|
||||
length processed by the software fallback. Its default is being set to
|
||||
512 bytes, a little lower than the break-even point, to balance the cost
|
||||
in CPU usage.
|
||||
|
||||
Signed-off-by: Eneas U de Queiroz <cotequeiroz@gmail.com>
|
||||
|
||||
--- a/drivers/crypto/Kconfig
|
||||
+++ b/drivers/crypto/Kconfig
|
||||
@@ -592,6 +592,29 @@ config CRYPTO_DEV_QCE
|
||||
hardware. To compile this driver as a module, choose M here. The
|
||||
module will be called qcrypto.
|
||||
|
||||
+config CRYPTO_DEV_QCE_SW_MAX_LEN
|
||||
+ int "Default maximum request size to use software for AES"
|
||||
+ depends on CRYPTO_DEV_QCE && CRYPTO_DEV_QCE_SKCIPHER
|
||||
+ default 512
|
||||
+ help
|
||||
+ This sets the default maximum request size to perform AES requests
|
||||
+ using software instead of the crypto engine. It can be changed by
|
||||
+ setting the aes_sw_max_len parameter.
|
||||
+
|
||||
+ Small blocks are processed faster in software than hardware.
|
||||
+ Considering the 256-bit ciphers, software is 2-3 times faster than
|
||||
+ qce at 256-bytes, 30% faster at 512, and about even at 768-bytes.
|
||||
+ With 128-bit keys, the break-even point would be around 1024-bytes.
|
||||
+
|
||||
+ The default is set a little lower, to 512 bytes, to balance the
|
||||
+ cost in CPU usage. The minimum recommended setting is 16-bytes
|
||||
+ (1 AES block), since AES-GCM will fail if you set it lower.
|
||||
+ Setting this to zero will send all requests to the hardware.
|
||||
+
|
||||
+ Note that 192-bit keys are not supported by the hardware and are
|
||||
+ always processed by the software fallback, and all DES requests
|
||||
+ are done by the hardware.
|
||||
+
|
||||
config CRYPTO_DEV_VMX
|
||||
bool "Support for VMX cryptographic acceleration instructions"
|
||||
depends on PPC64 && VSX
|
||||
--- a/drivers/crypto/qce/skcipher.c
|
||||
+++ b/drivers/crypto/qce/skcipher.c
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/interrupt.h>
|
||||
+#include <linux/moduleparam.h>
|
||||
#include <linux/types.h>
|
||||
#include <crypto/aes.h>
|
||||
#include <crypto/des.h>
|
||||
@@ -20,6 +21,13 @@
|
||||
|
||||
#include "cipher.h"
|
||||
|
||||
+static unsigned int aes_sw_max_len = CONFIG_CRYPTO_DEV_QCE_SW_MAX_LEN;
|
||||
+module_param(aes_sw_max_len, uint, 0644);
|
||||
+MODULE_PARM_DESC(aes_sw_max_len,
|
||||
+ "Only use hardware for AES requests larger than this "
|
||||
+ "[0=always use hardware; anything <16 breaks AES-GCM; default="
|
||||
+ __stringify(CONFIG_CRYPTO_DEV_QCE_SOFT_THRESHOLD)"]");
|
||||
+
|
||||
static LIST_HEAD(skcipher_algs);
|
||||
|
||||
static void qce_skcipher_done(void *data)
|
||||
@@ -170,15 +178,7 @@ static int qce_skcipher_setkey(struct cr
|
||||
if (!key || !keylen)
|
||||
return -EINVAL;
|
||||
|
||||
- if (IS_AES(flags)) {
|
||||
- switch (IS_XTS(flags) ? keylen >> 1 : keylen) {
|
||||
- case AES_KEYSIZE_128:
|
||||
- case AES_KEYSIZE_256:
|
||||
- break;
|
||||
- default:
|
||||
- goto fallback;
|
||||
- }
|
||||
- } else if (IS_DES(flags)) {
|
||||
+ if (IS_DES(flags)) {
|
||||
u32 tmp[DES_EXPKEY_WORDS];
|
||||
|
||||
ret = des_ekey(tmp, key);
|
||||
@@ -189,8 +189,8 @@ static int qce_skcipher_setkey(struct cr
|
||||
|
||||
ctx->enc_keylen = keylen;
|
||||
memcpy(ctx->enc_key, key, keylen);
|
||||
- return 0;
|
||||
-fallback:
|
||||
+ if (!IS_AES(flags))
|
||||
+ return 0;
|
||||
ret = crypto_skcipher_setkey(ctx->fallback, key, keylen);
|
||||
if (!ret)
|
||||
ctx->enc_keylen = keylen;
|
||||
@@ -213,8 +213,9 @@ static int qce_skcipher_crypt(struct skc
|
||||
rctx->flags |= encrypt ? QCE_ENCRYPT : QCE_DECRYPT;
|
||||
keylen = IS_XTS(rctx->flags) ? ctx->enc_keylen >> 1 : ctx->enc_keylen;
|
||||
|
||||
- if (IS_AES(rctx->flags) && keylen != AES_KEYSIZE_128 &&
|
||||
- keylen != AES_KEYSIZE_256) {
|
||||
+ if (IS_AES(rctx->flags) &&
|
||||
+ ((keylen != AES_KEYSIZE_128 && keylen != AES_KEYSIZE_256) ||
|
||||
+ req->cryptlen <= aes_sw_max_len)) {
|
||||
SKCIPHER_REQUEST_ON_STACK(subreq, ctx->fallback);
|
||||
|
||||
skcipher_request_set_tfm(subreq, ctx->fallback);
|
||||
@ -1,53 +0,0 @@
|
||||
From bbf2b1cf22dc98f3df33b6666df046dfb9564d91 Mon Sep 17 00:00:00 2001
|
||||
From: Eneas U de Queiroz <cotequeiroz@gmail.com>
|
||||
Date: Wed, 5 Feb 2020 13:42:25 -0300
|
||||
Subject: [PATCH] crypto: qce - handle AES-XTS cases that qce fails
|
||||
|
||||
QCE hangs when presented with an AES-XTS request whose length is larger
|
||||
than QCE_SECTOR_SIZE (512-bytes), and is not a multiple of it. Let the
|
||||
fallback cipher handle them.
|
||||
|
||||
Signed-off-by: Eneas U de Queiroz <cotequeiroz@gmail.com>
|
||||
|
||||
--- a/drivers/crypto/qce/common.c
|
||||
+++ b/drivers/crypto/qce/common.c
|
||||
@@ -23,8 +23,6 @@
|
||||
#include "regs-v5.h"
|
||||
#include "sha.h"
|
||||
|
||||
-#define QCE_SECTOR_SIZE 512
|
||||
-
|
||||
static inline u32 qce_read(struct qce_device *qce, u32 offset)
|
||||
{
|
||||
return readl(qce->base + offset);
|
||||
--- a/drivers/crypto/qce/common.h
|
||||
+++ b/drivers/crypto/qce/common.h
|
||||
@@ -20,6 +20,9 @@
|
||||
#include <crypto/hash.h>
|
||||
#include <crypto/internal/skcipher.h>
|
||||
|
||||
+/* xts du size */
|
||||
+#define QCE_SECTOR_SIZE 512
|
||||
+
|
||||
/* key size in bytes */
|
||||
#define QCE_SHA_HMAC_KEY_SIZE 64
|
||||
#define QCE_MAX_CIPHER_KEY_SIZE AES_KEYSIZE_256
|
||||
--- a/drivers/crypto/qce/skcipher.c
|
||||
+++ b/drivers/crypto/qce/skcipher.c
|
||||
@@ -213,9 +213,14 @@ static int qce_skcipher_crypt(struct skc
|
||||
rctx->flags |= encrypt ? QCE_ENCRYPT : QCE_DECRYPT;
|
||||
keylen = IS_XTS(rctx->flags) ? ctx->enc_keylen >> 1 : ctx->enc_keylen;
|
||||
|
||||
+ /* qce is hanging when AES-XTS request len > QCE_SECTOR_SIZE and
|
||||
+ * is not a multiple of it; pass such requests to the fallback
|
||||
+ */
|
||||
if (IS_AES(rctx->flags) &&
|
||||
- ((keylen != AES_KEYSIZE_128 && keylen != AES_KEYSIZE_256) ||
|
||||
- req->cryptlen <= aes_sw_max_len)) {
|
||||
+ (((keylen != AES_KEYSIZE_128 && keylen != AES_KEYSIZE_256) ||
|
||||
+ req->cryptlen <= aes_sw_max_len) ||
|
||||
+ (IS_XTS(rctx->flags) && req->cryptlen > QCE_SECTOR_SIZE &&
|
||||
+ req->cryptlen % QCE_SECTOR_SIZE))) {
|
||||
SKCIPHER_REQUEST_ON_STACK(subreq, ctx->fallback);
|
||||
|
||||
skcipher_request_set_tfm(subreq, ctx->fallback);
|
||||
@ -1,406 +0,0 @@
|
||||
From 62134842498927a0fcc19798a615340a7a6a9e62 Mon Sep 17 00:00:00 2001
|
||||
From: Eneas U de Queiroz <cotequeiroz@gmail.com>
|
||||
Date: Mon, 28 Oct 2019 15:17:19 -0300
|
||||
Subject: [PATCH] crypto: qce - allow building only hashes/ciphers
|
||||
|
||||
Signed-off-by: Eneas U de Queiroz <cotequeiroz@gmail.com>
|
||||
|
||||
--- a/drivers/crypto/Kconfig
|
||||
+++ b/drivers/crypto/Kconfig
|
||||
@@ -580,6 +580,14 @@ config CRYPTO_DEV_CAVIUM_ZIP
|
||||
config CRYPTO_DEV_QCE
|
||||
tristate "Qualcomm crypto engine accelerator"
|
||||
depends on (ARCH_QCOM || COMPILE_TEST) && HAS_DMA && HAS_IOMEM
|
||||
+ help
|
||||
+ This driver supports Qualcomm crypto engine accelerator
|
||||
+ hardware. To compile this driver as a module, choose M here. The
|
||||
+ module will be called qcrypto.
|
||||
+
|
||||
+config CRYPTO_DEV_QCE_SKCIPHER
|
||||
+ bool
|
||||
+ depends on CRYPTO_DEV_QCE
|
||||
select CRYPTO_AES
|
||||
select CRYPTO_DES
|
||||
select CRYPTO_ECB
|
||||
@@ -587,10 +595,57 @@ config CRYPTO_DEV_QCE
|
||||
select CRYPTO_XTS
|
||||
select CRYPTO_CTR
|
||||
select CRYPTO_BLKCIPHER
|
||||
+
|
||||
+config CRYPTO_DEV_QCE_SHA
|
||||
+ bool
|
||||
+ depends on CRYPTO_DEV_QCE
|
||||
+
|
||||
+choice
|
||||
+ prompt "Algorithms enabled for QCE acceleration"
|
||||
+ default CRYPTO_DEV_QCE_ENABLE_ALL
|
||||
+ depends on CRYPTO_DEV_QCE
|
||||
help
|
||||
- This driver supports Qualcomm crypto engine accelerator
|
||||
- hardware. To compile this driver as a module, choose M here. The
|
||||
- module will be called qcrypto.
|
||||
+ This option allows to choose whether to build support for all algorihtms
|
||||
+ (default), hashes-only, or skciphers-only.
|
||||
+
|
||||
+ The QCE engine does not appear to scale as well as the CPU to handle
|
||||
+ multiple crypto requests. While the ipq40xx chips have 4-core CPUs, the
|
||||
+ QCE handles only 2 requests in parallel.
|
||||
+
|
||||
+ Ipsec throughput seems to improve when disabling either family of
|
||||
+ algorithms, sharing the load with the CPU. Enabling skciphers-only
|
||||
+ appears to work best.
|
||||
+
|
||||
+ config CRYPTO_DEV_QCE_ENABLE_ALL
|
||||
+ bool "All supported algorithms"
|
||||
+ select CRYPTO_DEV_QCE_SKCIPHER
|
||||
+ select CRYPTO_DEV_QCE_SHA
|
||||
+ help
|
||||
+ Enable all supported algorithms:
|
||||
+ - AES (CBC, CTR, ECB, XTS)
|
||||
+ - 3DES (CBC, ECB)
|
||||
+ - DES (CBC, ECB)
|
||||
+ - SHA1, HMAC-SHA1
|
||||
+ - SHA256, HMAC-SHA256
|
||||
+
|
||||
+ config CRYPTO_DEV_QCE_ENABLE_SKCIPHER
|
||||
+ bool "Symmetric-key ciphers only"
|
||||
+ select CRYPTO_DEV_QCE_SKCIPHER
|
||||
+ help
|
||||
+ Enable symmetric-key ciphers only:
|
||||
+ - AES (CBC, CTR, ECB, XTS)
|
||||
+ - 3DES (ECB, CBC)
|
||||
+ - DES (ECB, CBC)
|
||||
+
|
||||
+ config CRYPTO_DEV_QCE_ENABLE_SHA
|
||||
+ bool "Hash/HMAC only"
|
||||
+ select CRYPTO_DEV_QCE_SHA
|
||||
+ help
|
||||
+ Enable hashes/HMAC algorithms only:
|
||||
+ - SHA1, HMAC-SHA1
|
||||
+ - SHA256, HMAC-SHA256
|
||||
+
|
||||
+endchoice
|
||||
|
||||
config CRYPTO_DEV_QCE_SW_MAX_LEN
|
||||
int "Default maximum request size to use software for AES"
|
||||
--- a/drivers/crypto/qce/Makefile
|
||||
+++ b/drivers/crypto/qce/Makefile
|
||||
@@ -2,6 +2,7 @@
|
||||
obj-$(CONFIG_CRYPTO_DEV_QCE) += qcrypto.o
|
||||
qcrypto-objs := core.o \
|
||||
common.o \
|
||||
- dma.o \
|
||||
- sha.o \
|
||||
- skcipher.o
|
||||
+ dma.o
|
||||
+
|
||||
+qcrypto-$(CONFIG_CRYPTO_DEV_QCE_SHA) += sha.o
|
||||
+qcrypto-$(CONFIG_CRYPTO_DEV_QCE_SKCIPHER) += skcipher.o
|
||||
--- a/drivers/crypto/qce/common.c
|
||||
+++ b/drivers/crypto/qce/common.c
|
||||
@@ -51,52 +51,56 @@ qce_clear_array(struct qce_device *qce,
|
||||
qce_write(qce, offset + i * sizeof(u32), 0);
|
||||
}
|
||||
|
||||
-static u32 qce_encr_cfg(unsigned long flags, u32 aes_key_size)
|
||||
+static u32 qce_config_reg(struct qce_device *qce, int little)
|
||||
{
|
||||
- u32 cfg = 0;
|
||||
+ u32 beats = (qce->burst_size >> 3) - 1;
|
||||
+ u32 pipe_pair = qce->pipe_pair_id;
|
||||
+ u32 config;
|
||||
|
||||
- if (IS_AES(flags)) {
|
||||
- if (aes_key_size == AES_KEYSIZE_128)
|
||||
- cfg |= ENCR_KEY_SZ_AES128 << ENCR_KEY_SZ_SHIFT;
|
||||
- else if (aes_key_size == AES_KEYSIZE_256)
|
||||
- cfg |= ENCR_KEY_SZ_AES256 << ENCR_KEY_SZ_SHIFT;
|
||||
- }
|
||||
+ config = (beats << REQ_SIZE_SHIFT) & REQ_SIZE_MASK;
|
||||
+ config |= BIT(MASK_DOUT_INTR_SHIFT) | BIT(MASK_DIN_INTR_SHIFT) |
|
||||
+ BIT(MASK_OP_DONE_INTR_SHIFT) | BIT(MASK_ERR_INTR_SHIFT);
|
||||
+ config |= (pipe_pair << PIPE_SET_SELECT_SHIFT) & PIPE_SET_SELECT_MASK;
|
||||
+ config &= ~HIGH_SPD_EN_N_SHIFT;
|
||||
|
||||
- if (IS_AES(flags))
|
||||
- cfg |= ENCR_ALG_AES << ENCR_ALG_SHIFT;
|
||||
- else if (IS_DES(flags) || IS_3DES(flags))
|
||||
- cfg |= ENCR_ALG_DES << ENCR_ALG_SHIFT;
|
||||
+ if (little)
|
||||
+ config |= BIT(LITTLE_ENDIAN_MODE_SHIFT);
|
||||
|
||||
- if (IS_DES(flags))
|
||||
- cfg |= ENCR_KEY_SZ_DES << ENCR_KEY_SZ_SHIFT;
|
||||
+ return config;
|
||||
+}
|
||||
|
||||
- if (IS_3DES(flags))
|
||||
- cfg |= ENCR_KEY_SZ_3DES << ENCR_KEY_SZ_SHIFT;
|
||||
+void qce_cpu_to_be32p_array(__be32 *dst, const u8 *src, unsigned int len)
|
||||
+{
|
||||
+ __be32 *d = dst;
|
||||
+ const u8 *s = src;
|
||||
+ unsigned int n;
|
||||
|
||||
- switch (flags & QCE_MODE_MASK) {
|
||||
- case QCE_MODE_ECB:
|
||||
- cfg |= ENCR_MODE_ECB << ENCR_MODE_SHIFT;
|
||||
- break;
|
||||
- case QCE_MODE_CBC:
|
||||
- cfg |= ENCR_MODE_CBC << ENCR_MODE_SHIFT;
|
||||
- break;
|
||||
- case QCE_MODE_CTR:
|
||||
- cfg |= ENCR_MODE_CTR << ENCR_MODE_SHIFT;
|
||||
- break;
|
||||
- case QCE_MODE_XTS:
|
||||
- cfg |= ENCR_MODE_XTS << ENCR_MODE_SHIFT;
|
||||
- break;
|
||||
- case QCE_MODE_CCM:
|
||||
- cfg |= ENCR_MODE_CCM << ENCR_MODE_SHIFT;
|
||||
- cfg |= LAST_CCM_XFR << LAST_CCM_SHIFT;
|
||||
- break;
|
||||
- default:
|
||||
- return ~0;
|
||||
+ n = len / sizeof(u32);
|
||||
+ for (; n > 0; n--) {
|
||||
+ *d = cpu_to_be32p((const __u32 *) s);
|
||||
+ s += sizeof(__u32);
|
||||
+ d++;
|
||||
}
|
||||
+}
|
||||
|
||||
- return cfg;
|
||||
+static void qce_setup_config(struct qce_device *qce)
|
||||
+{
|
||||
+ u32 config;
|
||||
+
|
||||
+ /* get big endianness */
|
||||
+ config = qce_config_reg(qce, 0);
|
||||
+
|
||||
+ /* clear status */
|
||||
+ qce_write(qce, REG_STATUS, 0);
|
||||
+ qce_write(qce, REG_CONFIG, config);
|
||||
+}
|
||||
+
|
||||
+static inline void qce_crypto_go(struct qce_device *qce)
|
||||
+{
|
||||
+ qce_write(qce, REG_GOPROC, BIT(GO_SHIFT) | BIT(RESULTS_DUMP_SHIFT));
|
||||
}
|
||||
|
||||
+#ifdef CONFIG_CRYPTO_DEV_QCE_SHA
|
||||
static u32 qce_auth_cfg(unsigned long flags, u32 key_size)
|
||||
{
|
||||
u32 cfg = 0;
|
||||
@@ -143,88 +147,6 @@ static u32 qce_auth_cfg(unsigned long fl
|
||||
return cfg;
|
||||
}
|
||||
|
||||
-static u32 qce_config_reg(struct qce_device *qce, int little)
|
||||
-{
|
||||
- u32 beats = (qce->burst_size >> 3) - 1;
|
||||
- u32 pipe_pair = qce->pipe_pair_id;
|
||||
- u32 config;
|
||||
-
|
||||
- config = (beats << REQ_SIZE_SHIFT) & REQ_SIZE_MASK;
|
||||
- config |= BIT(MASK_DOUT_INTR_SHIFT) | BIT(MASK_DIN_INTR_SHIFT) |
|
||||
- BIT(MASK_OP_DONE_INTR_SHIFT) | BIT(MASK_ERR_INTR_SHIFT);
|
||||
- config |= (pipe_pair << PIPE_SET_SELECT_SHIFT) & PIPE_SET_SELECT_MASK;
|
||||
- config &= ~HIGH_SPD_EN_N_SHIFT;
|
||||
-
|
||||
- if (little)
|
||||
- config |= BIT(LITTLE_ENDIAN_MODE_SHIFT);
|
||||
-
|
||||
- return config;
|
||||
-}
|
||||
-
|
||||
-void qce_cpu_to_be32p_array(__be32 *dst, const u8 *src, unsigned int len)
|
||||
-{
|
||||
- __be32 *d = dst;
|
||||
- const u8 *s = src;
|
||||
- unsigned int n;
|
||||
-
|
||||
- n = len / sizeof(u32);
|
||||
- for (; n > 0; n--) {
|
||||
- *d = cpu_to_be32p((const __u32 *) s);
|
||||
- s += sizeof(__u32);
|
||||
- d++;
|
||||
- }
|
||||
-}
|
||||
-
|
||||
-static void qce_xts_swapiv(__be32 *dst, const u8 *src, unsigned int ivsize)
|
||||
-{
|
||||
- u8 swap[QCE_AES_IV_LENGTH];
|
||||
- u32 i, j;
|
||||
-
|
||||
- if (ivsize > QCE_AES_IV_LENGTH)
|
||||
- return;
|
||||
-
|
||||
- memset(swap, 0, QCE_AES_IV_LENGTH);
|
||||
-
|
||||
- for (i = (QCE_AES_IV_LENGTH - ivsize), j = ivsize - 1;
|
||||
- i < QCE_AES_IV_LENGTH; i++, j--)
|
||||
- swap[i] = src[j];
|
||||
-
|
||||
- qce_cpu_to_be32p_array(dst, swap, QCE_AES_IV_LENGTH);
|
||||
-}
|
||||
-
|
||||
-static void qce_xtskey(struct qce_device *qce, const u8 *enckey,
|
||||
- unsigned int enckeylen, unsigned int cryptlen)
|
||||
-{
|
||||
- u32 xtskey[QCE_MAX_CIPHER_KEY_SIZE / sizeof(u32)] = {0};
|
||||
- unsigned int xtsklen = enckeylen / (2 * sizeof(u32));
|
||||
- unsigned int xtsdusize;
|
||||
-
|
||||
- qce_cpu_to_be32p_array((__be32 *)xtskey, enckey + enckeylen / 2,
|
||||
- enckeylen / 2);
|
||||
- qce_write_array(qce, REG_ENCR_XTS_KEY0, xtskey, xtsklen);
|
||||
-
|
||||
- /* xts du size 512B */
|
||||
- xtsdusize = min_t(u32, QCE_SECTOR_SIZE, cryptlen);
|
||||
- qce_write(qce, REG_ENCR_XTS_DU_SIZE, xtsdusize);
|
||||
-}
|
||||
-
|
||||
-static void qce_setup_config(struct qce_device *qce)
|
||||
-{
|
||||
- u32 config;
|
||||
-
|
||||
- /* get big endianness */
|
||||
- config = qce_config_reg(qce, 0);
|
||||
-
|
||||
- /* clear status */
|
||||
- qce_write(qce, REG_STATUS, 0);
|
||||
- qce_write(qce, REG_CONFIG, config);
|
||||
-}
|
||||
-
|
||||
-static inline void qce_crypto_go(struct qce_device *qce)
|
||||
-{
|
||||
- qce_write(qce, REG_GOPROC, BIT(GO_SHIFT) | BIT(RESULTS_DUMP_SHIFT));
|
||||
-}
|
||||
-
|
||||
static int qce_setup_regs_ahash(struct crypto_async_request *async_req,
|
||||
u32 totallen, u32 offset)
|
||||
{
|
||||
@@ -309,6 +231,87 @@ go_proc:
|
||||
|
||||
return 0;
|
||||
}
|
||||
+#endif
|
||||
+
|
||||
+#ifdef CONFIG_CRYPTO_DEV_QCE_SKCIPHER
|
||||
+static u32 qce_encr_cfg(unsigned long flags, u32 aes_key_size)
|
||||
+{
|
||||
+ u32 cfg = 0;
|
||||
+
|
||||
+ if (IS_AES(flags)) {
|
||||
+ if (aes_key_size == AES_KEYSIZE_128)
|
||||
+ cfg |= ENCR_KEY_SZ_AES128 << ENCR_KEY_SZ_SHIFT;
|
||||
+ else if (aes_key_size == AES_KEYSIZE_256)
|
||||
+ cfg |= ENCR_KEY_SZ_AES256 << ENCR_KEY_SZ_SHIFT;
|
||||
+ }
|
||||
+
|
||||
+ if (IS_AES(flags))
|
||||
+ cfg |= ENCR_ALG_AES << ENCR_ALG_SHIFT;
|
||||
+ else if (IS_DES(flags) || IS_3DES(flags))
|
||||
+ cfg |= ENCR_ALG_DES << ENCR_ALG_SHIFT;
|
||||
+
|
||||
+ if (IS_DES(flags))
|
||||
+ cfg |= ENCR_KEY_SZ_DES << ENCR_KEY_SZ_SHIFT;
|
||||
+
|
||||
+ if (IS_3DES(flags))
|
||||
+ cfg |= ENCR_KEY_SZ_3DES << ENCR_KEY_SZ_SHIFT;
|
||||
+
|
||||
+ switch (flags & QCE_MODE_MASK) {
|
||||
+ case QCE_MODE_ECB:
|
||||
+ cfg |= ENCR_MODE_ECB << ENCR_MODE_SHIFT;
|
||||
+ break;
|
||||
+ case QCE_MODE_CBC:
|
||||
+ cfg |= ENCR_MODE_CBC << ENCR_MODE_SHIFT;
|
||||
+ break;
|
||||
+ case QCE_MODE_CTR:
|
||||
+ cfg |= ENCR_MODE_CTR << ENCR_MODE_SHIFT;
|
||||
+ break;
|
||||
+ case QCE_MODE_XTS:
|
||||
+ cfg |= ENCR_MODE_XTS << ENCR_MODE_SHIFT;
|
||||
+ break;
|
||||
+ case QCE_MODE_CCM:
|
||||
+ cfg |= ENCR_MODE_CCM << ENCR_MODE_SHIFT;
|
||||
+ cfg |= LAST_CCM_XFR << LAST_CCM_SHIFT;
|
||||
+ break;
|
||||
+ default:
|
||||
+ return ~0;
|
||||
+ }
|
||||
+
|
||||
+ return cfg;
|
||||
+}
|
||||
+
|
||||
+static void qce_xts_swapiv(__be32 *dst, const u8 *src, unsigned int ivsize)
|
||||
+{
|
||||
+ u8 swap[QCE_AES_IV_LENGTH];
|
||||
+ u32 i, j;
|
||||
+
|
||||
+ if (ivsize > QCE_AES_IV_LENGTH)
|
||||
+ return;
|
||||
+
|
||||
+ memset(swap, 0, QCE_AES_IV_LENGTH);
|
||||
+
|
||||
+ for (i = (QCE_AES_IV_LENGTH - ivsize), j = ivsize - 1;
|
||||
+ i < QCE_AES_IV_LENGTH; i++, j--)
|
||||
+ swap[i] = src[j];
|
||||
+
|
||||
+ qce_cpu_to_be32p_array(dst, swap, QCE_AES_IV_LENGTH);
|
||||
+}
|
||||
+
|
||||
+static void qce_xtskey(struct qce_device *qce, const u8 *enckey,
|
||||
+ unsigned int enckeylen, unsigned int cryptlen)
|
||||
+{
|
||||
+ u32 xtskey[QCE_MAX_CIPHER_KEY_SIZE / sizeof(u32)] = {0};
|
||||
+ unsigned int xtsklen = enckeylen / (2 * sizeof(u32));
|
||||
+ unsigned int xtsdusize;
|
||||
+
|
||||
+ qce_cpu_to_be32p_array((__be32 *)xtskey, enckey + enckeylen / 2,
|
||||
+ enckeylen / 2);
|
||||
+ qce_write_array(qce, REG_ENCR_XTS_KEY0, xtskey, xtsklen);
|
||||
+
|
||||
+ /* xts du size 512B */
|
||||
+ xtsdusize = min_t(u32, QCE_SECTOR_SIZE, cryptlen);
|
||||
+ qce_write(qce, REG_ENCR_XTS_DU_SIZE, xtsdusize);
|
||||
+}
|
||||
|
||||
static int qce_setup_regs_skcipher(struct crypto_async_request *async_req,
|
||||
u32 totallen, u32 offset)
|
||||
@@ -390,15 +393,20 @@ static int qce_setup_regs_skcipher(struc
|
||||
|
||||
return 0;
|
||||
}
|
||||
+#endif
|
||||
|
||||
int qce_start(struct crypto_async_request *async_req, u32 type, u32 totallen,
|
||||
u32 offset)
|
||||
{
|
||||
switch (type) {
|
||||
+#ifdef CONFIG_CRYPTO_DEV_QCE_SKCIPHER
|
||||
case CRYPTO_ALG_TYPE_SKCIPHER:
|
||||
return qce_setup_regs_skcipher(async_req, totallen, offset);
|
||||
+#endif
|
||||
+#ifdef CONFIG_CRYPTO_DEV_QCE_SHA
|
||||
case CRYPTO_ALG_TYPE_AHASH:
|
||||
return qce_setup_regs_ahash(async_req, totallen, offset);
|
||||
+#endif
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
--- a/drivers/crypto/qce/core.c
|
||||
+++ b/drivers/crypto/qce/core.c
|
||||
@@ -29,8 +29,12 @@
|
||||
#define QCE_QUEUE_LENGTH 1
|
||||
|
||||
static const struct qce_algo_ops *qce_ops[] = {
|
||||
+#ifdef CONFIG_CRYPTO_DEV_QCE_SKCIPHER
|
||||
&skcipher_ops,
|
||||
+#endif
|
||||
+#ifdef CONFIG_CRYPTO_DEV_QCE_SHA
|
||||
&ahash_ops,
|
||||
+#endif
|
||||
};
|
||||
|
||||
static void qce_unregister_algs(struct qce_device *qce)
|
||||
@ -1,26 +0,0 @@
|
||||
From 341844c7e06afccd64261719fa388339a589b0a4 Mon Sep 17 00:00:00 2001
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Sun, 22 Jul 2018 12:53:04 +0200
|
||||
Subject: [PATCH] soc: qcom: spm: add SCM probe dependency
|
||||
|
||||
Check for SCM availability before attempting to use SPM. SPM probe will
|
||||
fail otherwise.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
Signed-off-by: John Crispin <john@phrozen.org>
|
||||
---
|
||||
drivers/soc/qcom/spm.c | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
--- a/drivers/soc/qcom/spm.c
|
||||
+++ b/drivers/soc/qcom/spm.c
|
||||
@@ -219,6 +219,9 @@ static int __init qcom_cpuidle_init(stru
|
||||
cpumask_t mask;
|
||||
bool use_scm_power_down = false;
|
||||
|
||||
+ if (!qcom_scm_is_available())
|
||||
+ return -EPROBE_DEFER;
|
||||
+
|
||||
for (i = 0; ; i++) {
|
||||
state_node = of_parse_phandle(cpu_node, "cpu-idle-states", i);
|
||||
if (!state_node)
|
||||
@ -1,109 +0,0 @@
|
||||
From 364123029d8d547336323fbd3d659ecd0bba913f Mon Sep 17 00:00:00 2001
|
||||
From: Matthew McClintock <mmcclint@codeaurora.org>
|
||||
Date: Mon, 23 Jul 2018 08:41:02 +0200
|
||||
Subject: [PATCH 5/8] qcom: ipq4019: use v2 of the kpss bringup mechanism
|
||||
|
||||
v1 was the incorrect choice here and sometimes the board
|
||||
would not come up properly.
|
||||
|
||||
Signed-off-by: Matthew McClintock <mmcclint@codeaurora.org>
|
||||
Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
|
||||
Signed-off-by: John Crispin <john@phrozen.org>
|
||||
---
|
||||
arch/arm/boot/dts/qcom-ipq4019.dtsi | 25 +++++++++++++++++--------
|
||||
1 file changed, 17 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/arch/arm/boot/dts/qcom-ipq4019.dtsi
|
||||
+++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi
|
||||
@@ -34,7 +34,8 @@
|
||||
cpu@0 {
|
||||
device_type = "cpu";
|
||||
compatible = "arm,cortex-a7";
|
||||
- enable-method = "qcom,kpss-acc-v1";
|
||||
+ enable-method = "qcom,kpss-acc-v2";
|
||||
+ next-level-cache = <&L2>;
|
||||
qcom,acc = <&acc0>;
|
||||
qcom,saw = <&saw0>;
|
||||
reg = <0x0>;
|
||||
@@ -53,7 +54,8 @@
|
||||
cpu@1 {
|
||||
device_type = "cpu";
|
||||
compatible = "arm,cortex-a7";
|
||||
- enable-method = "qcom,kpss-acc-v1";
|
||||
+ enable-method = "qcom,kpss-acc-v2";
|
||||
+ next-level-cache = <&L2>;
|
||||
qcom,acc = <&acc1>;
|
||||
qcom,saw = <&saw1>;
|
||||
reg = <0x1>;
|
||||
@@ -64,7 +66,8 @@
|
||||
cpu@2 {
|
||||
device_type = "cpu";
|
||||
compatible = "arm,cortex-a7";
|
||||
- enable-method = "qcom,kpss-acc-v1";
|
||||
+ enable-method = "qcom,kpss-acc-v2";
|
||||
+ next-level-cache = <&L2>;
|
||||
qcom,acc = <&acc2>;
|
||||
qcom,saw = <&saw2>;
|
||||
reg = <0x2>;
|
||||
@@ -75,13 +78,20 @@
|
||||
cpu@3 {
|
||||
device_type = "cpu";
|
||||
compatible = "arm,cortex-a7";
|
||||
- enable-method = "qcom,kpss-acc-v1";
|
||||
+ enable-method = "qcom,kpss-acc-v2";
|
||||
+ next-level-cache = <&L2>;
|
||||
qcom,acc = <&acc3>;
|
||||
qcom,saw = <&saw3>;
|
||||
reg = <0x3>;
|
||||
clocks = <&gcc GCC_APPS_CLK_SRC>;
|
||||
clock-frequency = <0>;
|
||||
};
|
||||
+
|
||||
+ L2: l2-cache {
|
||||
+ compatible = "cache";
|
||||
+ cache-level = <2>;
|
||||
+ qcom,saw = <&saw_l2>;
|
||||
+ };
|
||||
};
|
||||
|
||||
pmu {
|
||||
@@ -213,22 +223,22 @@
|
||||
};
|
||||
|
||||
acc0: clock-controller@b088000 {
|
||||
- compatible = "qcom,kpss-acc-v1";
|
||||
+ compatible = "qcom,kpss-acc-v2";
|
||||
reg = <0x0b088000 0x1000>, <0xb008000 0x1000>;
|
||||
};
|
||||
|
||||
acc1: clock-controller@b098000 {
|
||||
- compatible = "qcom,kpss-acc-v1";
|
||||
+ compatible = "qcom,kpss-acc-v2";
|
||||
reg = <0x0b098000 0x1000>, <0xb008000 0x1000>;
|
||||
};
|
||||
|
||||
acc2: clock-controller@b0a8000 {
|
||||
- compatible = "qcom,kpss-acc-v1";
|
||||
+ compatible = "qcom,kpss-acc-v2";
|
||||
reg = <0x0b0a8000 0x1000>, <0xb008000 0x1000>;
|
||||
};
|
||||
|
||||
acc3: clock-controller@b0b8000 {
|
||||
- compatible = "qcom,kpss-acc-v1";
|
||||
+ compatible = "qcom,kpss-acc-v2";
|
||||
reg = <0x0b0b8000 0x1000>, <0xb008000 0x1000>;
|
||||
};
|
||||
|
||||
@@ -256,6 +266,12 @@
|
||||
regulator;
|
||||
};
|
||||
|
||||
+ saw_l2: regulator@b012000 {
|
||||
+ compatible = "qcom,saw2";
|
||||
+ reg = <0xb012000 0x1000>;
|
||||
+ regulator;
|
||||
+ };
|
||||
+
|
||||
serial@78af000 {
|
||||
compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
|
||||
reg = <0x78af000 0x200>;
|
||||
@ -1,89 +0,0 @@
|
||||
From 544af73985cd14b450bb8e8a6c22b89a555ac729 Mon Sep 17 00:00:00 2001
|
||||
From: Matthew McClintock <mmcclint@codeaurora.org>
|
||||
Date: Mon, 23 Jul 2018 09:10:35 +0200
|
||||
Subject: [PATCH 6/8] qcom: ipq4019: add cpu operating points for cpufreq
|
||||
support
|
||||
|
||||
This adds some operating points for cpu frequeny scaling
|
||||
|
||||
Signed-off-by: Matthew McClintock <mmcclint@codeaurora.org>
|
||||
Signed-off-by: John Crispin <john@phrozen.org>
|
||||
---
|
||||
arch/arm/boot/dts/qcom-ipq4019.dtsi | 34 ++++++++++++++++++++++++++--------
|
||||
1 file changed, 30 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/arch/arm/boot/dts/qcom-ipq4019.dtsi
|
||||
+++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi
|
||||
@@ -41,14 +41,7 @@
|
||||
reg = <0x0>;
|
||||
clocks = <&gcc GCC_APPS_CLK_SRC>;
|
||||
clock-frequency = <0>;
|
||||
- operating-points = <
|
||||
- /* kHz uV (fixed) */
|
||||
- 48000 1100000
|
||||
- 200000 1100000
|
||||
- 500000 1100000
|
||||
- 666000 1100000
|
||||
- >;
|
||||
- clock-latency = <256000>;
|
||||
+ operating-points-v2 = <&cpu0_opp_table>;
|
||||
};
|
||||
|
||||
cpu@1 {
|
||||
@@ -61,6 +54,7 @@
|
||||
reg = <0x1>;
|
||||
clocks = <&gcc GCC_APPS_CLK_SRC>;
|
||||
clock-frequency = <0>;
|
||||
+ operating-points-v2 = <&cpu0_opp_table>;
|
||||
};
|
||||
|
||||
cpu@2 {
|
||||
@@ -73,6 +67,7 @@
|
||||
reg = <0x2>;
|
||||
clocks = <&gcc GCC_APPS_CLK_SRC>;
|
||||
clock-frequency = <0>;
|
||||
+ operating-points-v2 = <&cpu0_opp_table>;
|
||||
};
|
||||
|
||||
cpu@3 {
|
||||
@@ -85,6 +80,7 @@
|
||||
reg = <0x3>;
|
||||
clocks = <&gcc GCC_APPS_CLK_SRC>;
|
||||
clock-frequency = <0>;
|
||||
+ operating-points-v2 = <&cpu0_opp_table>;
|
||||
};
|
||||
|
||||
L2: l2-cache {
|
||||
@@ -94,6 +90,32 @@
|
||||
};
|
||||
};
|
||||
|
||||
+ cpu0_opp_table: opp_table0 {
|
||||
+ compatible = "operating-points-v2";
|
||||
+ opp-shared;
|
||||
+
|
||||
+ opp-48000000 {
|
||||
+ opp-hz = /bits/ 64 <48000000>;
|
||||
+ clock-latency-ns = <256000>;
|
||||
+ opp-microvolt = <1100000>;
|
||||
+ };
|
||||
+ opp-200000000 {
|
||||
+ opp-hz = /bits/ 64 <200000000>;
|
||||
+ clock-latency-ns = <256000>;
|
||||
+ opp-microvolt = <1100000>;
|
||||
+ };
|
||||
+ opp-500000000 {
|
||||
+ opp-hz = /bits/ 64 <500000000>;
|
||||
+ clock-latency-ns = <256000>;
|
||||
+ opp-microvolt = <1100000>;
|
||||
+ };
|
||||
+ opp-716000000 {
|
||||
+ opp-hz = /bits/ 64 <716000000>;
|
||||
+ clock-latency-ns = <256000>;
|
||||
+ opp-microvolt = <1100000>;
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
pmu {
|
||||
compatible = "arm,cortex-a7-pmu";
|
||||
interrupts = <GIC_PPI 7 (GIC_CPU_MASK_SIMPLE(4) |
|
||||
@ -1,36 +0,0 @@
|
||||
From 89b43d59ec8c9cda588555eb1f2754dd19ef5144 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Lamparter <chunkeey@gmail.com>
|
||||
Date: Sun, 22 Jul 2018 12:07:57 +0200
|
||||
Subject: [PATCH 8/8] ARM: qcom: Add IPQ4019 SoC support
|
||||
|
||||
Add support for the Qualcomm Atheros IPQ4019 SoC.
|
||||
|
||||
Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
|
||||
Signed-off-by: John Crispin <john@phrozen.org>
|
||||
---
|
||||
arch/arm/Makefile | 1 +
|
||||
arch/arm/mach-qcom/Kconfig | 5 +++++
|
||||
2 files changed, 6 insertions(+)
|
||||
|
||||
--- a/arch/arm/Makefile
|
||||
+++ b/arch/arm/Makefile
|
||||
@@ -152,6 +152,7 @@ endif
|
||||
textofs-$(CONFIG_ARCH_MSM8X60) := 0x00208000
|
||||
textofs-$(CONFIG_ARCH_MSM8960) := 0x00208000
|
||||
textofs-$(CONFIG_ARCH_AXXIA) := 0x00308000
|
||||
+textofs-$(CONFIG_ARCH_IPQ40XX) := 0x00208000
|
||||
|
||||
# Machine directory name. This list is sorted alphanumerically
|
||||
# by CONFIG_* macro name.
|
||||
--- a/arch/arm/mach-qcom/Kconfig
|
||||
+++ b/arch/arm/mach-qcom/Kconfig
|
||||
@@ -27,4 +27,9 @@ config ARCH_MDM9615
|
||||
bool "Enable support for MDM9615"
|
||||
select CLKSRC_QCOM
|
||||
|
||||
+config ARCH_IPQ40XX
|
||||
+ bool "Enable support for IPQ40XX"
|
||||
+ select CLKSRC_QCOM
|
||||
+ select HAVE_ARM_ARCH_TIMER
|
||||
+
|
||||
endif
|
||||
@ -1,38 +0,0 @@
|
||||
From 5f01733dc755dfadfa51b7b3c6c160e632fc6002 Mon Sep 17 00:00:00 2001
|
||||
From: John Crispin <john@phrozen.org>
|
||||
Date: Tue, 24 Jul 2018 15:09:36 +0200
|
||||
Subject: [PATCH 1/3] dt-bindings: phy-qcom-ipq4019-usb: add binding document
|
||||
|
||||
This patch adds the binding documentation for the HS/SS USB PHY found
|
||||
inside Qualcom Dakota SoCs.
|
||||
|
||||
Signed-off-by: John Crispin <john@phrozen.org>
|
||||
---
|
||||
.../bindings/phy/phy-qcom-ipq4019-usb.txt | 21 +++++++++++++++++++++
|
||||
1 file changed, 21 insertions(+)
|
||||
create mode 100644 Documentation/devicetree/bindings/phy/phy-qcom-ipq4019-usb.txt
|
||||
|
||||
--- /dev/null
|
||||
+++ b/Documentation/devicetree/bindings/phy/phy-qcom-ipq4019-usb.txt
|
||||
@@ -0,0 +1,21 @@
|
||||
+Qualcom Dakota HS/SS USB PHY
|
||||
+
|
||||
+Required properties:
|
||||
+ - compatible: "qcom,usb-ss-ipq4019-phy",
|
||||
+ "qcom,usb-hs-ipq4019-phy"
|
||||
+ - reg: offset and length of the registers
|
||||
+ - #phy-cells: should be 0
|
||||
+ - resets: the reset controllers as listed below
|
||||
+ - reset-names: the names of the reset controllers
|
||||
+ "por_rst" - the POR reset line for SS and HS phys
|
||||
+ "srif_rst" - the SRIF reset line for HS phys
|
||||
+Example:
|
||||
+
|
||||
+hsphy@a8000 {
|
||||
+ compatible = "qcom,usb-hs-ipq4019-phy";
|
||||
+ phy-cells = <0>;
|
||||
+ reg = <0xa8000 0x40>;
|
||||
+ resets = <&gcc USB2_HSPHY_POR_ARES>,
|
||||
+ <&gcc USB2_HSPHY_S_ARES>;
|
||||
+ reset-names = "por_rst", "srif_rst";
|
||||
+};
|
||||
@ -1,233 +0,0 @@
|
||||
From 633f0e08498aebfdb932bd71319b4cb136709499 Mon Sep 17 00:00:00 2001
|
||||
From: John Crispin <john@phrozen.org>
|
||||
Date: Tue, 24 Jul 2018 14:45:49 +0200
|
||||
Subject: [PATCH 2/3] phy: qcom-ipq4019-usb: add driver for QCOM/IPQ4019
|
||||
|
||||
Add a driver to setup the USB phy on Qualcom Dakota SoCs.
|
||||
The driver sets up HS and SS phys. In case of HS some magic values need to
|
||||
be written to magic offsets. These were taken from the SDK driver.
|
||||
|
||||
Signed-off-by: John Crispin <john@phrozen.org>
|
||||
---
|
||||
drivers/phy/qualcomm/Kconfig | 7 ++
|
||||
drivers/phy/qualcomm/Makefile | 1 +
|
||||
drivers/phy/qualcomm/phy-qcom-ipq4019-usb.c | 188 ++++++++++++++++++++++++++++
|
||||
3 files changed, 196 insertions(+)
|
||||
create mode 100644 drivers/phy/qualcomm/phy-qcom-ipq4019-usb.c
|
||||
|
||||
--- a/drivers/phy/qualcomm/Kconfig
|
||||
+++ b/drivers/phy/qualcomm/Kconfig
|
||||
@@ -8,6 +8,13 @@ config PHY_QCOM_APQ8064_SATA
|
||||
depends on OF
|
||||
select GENERIC_PHY
|
||||
|
||||
+config PHY_QCOM_IPQ4019_USB
|
||||
+ tristate "Qualcomm IPQ4019 USB PHY module"
|
||||
+ depends on OF && ARCH_QCOM
|
||||
+ select GENERIC_PHY
|
||||
+ help
|
||||
+ Support for the USB PHY on QCOM IPQ4019/Dakota chipsets.
|
||||
+
|
||||
config PHY_QCOM_IPQ806X_SATA
|
||||
tristate "Qualcomm IPQ806x SATA SerDes/PHY driver"
|
||||
depends on ARCH_QCOM
|
||||
--- /dev/null
|
||||
+++ b/drivers/phy/qualcomm/phy-qcom-ipq4019-usb.c
|
||||
@@ -0,0 +1,188 @@
|
||||
+/*
|
||||
+ * Copyright (C) 2018 John Crispin <john@phrozen.org>
|
||||
+ *
|
||||
+ * Based on code from
|
||||
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify
|
||||
+ * it under the terms of the GNU General Public License as published by
|
||||
+ * the Free Software Foundation; either version 2 of the License, or
|
||||
+ * (at your option) any later version.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful,
|
||||
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
+ * GNU General Public License for more details.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/delay.h>
|
||||
+#include <linux/err.h>
|
||||
+#include <linux/io.h>
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/mutex.h>
|
||||
+#include <linux/of_platform.h>
|
||||
+#include <linux/phy/phy.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/reset.h>
|
||||
+
|
||||
+/*
|
||||
+ * Magic registers copied from the SDK driver code
|
||||
+ */
|
||||
+#define PHY_CTRL0_ADDR 0x000
|
||||
+#define PHY_CTRL1_ADDR 0x004
|
||||
+#define PHY_CTRL2_ADDR 0x008
|
||||
+#define PHY_CTRL3_ADDR 0x00C
|
||||
+#define PHY_CTRL4_ADDR 0x010
|
||||
+#define PHY_MISC_ADDR 0x024
|
||||
+#define PHY_IPG_ADDR 0x030
|
||||
+
|
||||
+#define PHY_CTRL0_VAL 0xA4600015
|
||||
+#define PHY_CTRL1_VAL 0x09500000
|
||||
+#define PHY_CTRL2_VAL 0x00058180
|
||||
+#define PHY_CTRL3_VAL 0x6DB6DCD6
|
||||
+#define PHY_CTRL4_VAL 0x836DB6DB
|
||||
+#define PHY_MISC_VAL 0x3803FB0C
|
||||
+#define PHY_IPG_VAL 0x47323232
|
||||
+
|
||||
+struct ipq4019_usb_phy {
|
||||
+ struct device *dev;
|
||||
+ struct phy *phy;
|
||||
+ void __iomem *base;
|
||||
+ struct reset_control *por_rst;
|
||||
+ struct reset_control *srif_rst;
|
||||
+};
|
||||
+
|
||||
+static int ipq4019_ss_phy_power_off(struct phy *_phy)
|
||||
+{
|
||||
+ struct ipq4019_usb_phy *phy = phy_get_drvdata(_phy);
|
||||
+
|
||||
+ reset_control_assert(phy->por_rst);
|
||||
+ msleep(10);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int ipq4019_ss_phy_power_on(struct phy *_phy)
|
||||
+{
|
||||
+ struct ipq4019_usb_phy *phy = phy_get_drvdata(_phy);
|
||||
+
|
||||
+ ipq4019_ss_phy_power_off(_phy);
|
||||
+
|
||||
+ reset_control_deassert(phy->por_rst);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static struct phy_ops ipq4019_usb_ss_phy_ops = {
|
||||
+ .power_on = ipq4019_ss_phy_power_on,
|
||||
+ .power_off = ipq4019_ss_phy_power_off,
|
||||
+};
|
||||
+
|
||||
+static int ipq4019_hs_phy_power_off(struct phy *_phy)
|
||||
+{
|
||||
+ struct ipq4019_usb_phy *phy = phy_get_drvdata(_phy);
|
||||
+
|
||||
+ reset_control_assert(phy->por_rst);
|
||||
+ msleep(10);
|
||||
+
|
||||
+ reset_control_assert(phy->srif_rst);
|
||||
+ msleep(10);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int ipq4019_hs_phy_power_on(struct phy *_phy)
|
||||
+{
|
||||
+ struct ipq4019_usb_phy *phy = phy_get_drvdata(_phy);
|
||||
+
|
||||
+ ipq4019_hs_phy_power_off(_phy);
|
||||
+
|
||||
+ reset_control_deassert(phy->srif_rst);
|
||||
+ msleep(10);
|
||||
+
|
||||
+ writel(PHY_CTRL0_VAL, phy->base + PHY_CTRL0_ADDR);
|
||||
+ writel(PHY_CTRL1_VAL, phy->base + PHY_CTRL1_ADDR);
|
||||
+ writel(PHY_CTRL2_VAL, phy->base + PHY_CTRL2_ADDR);
|
||||
+ writel(PHY_CTRL3_VAL, phy->base + PHY_CTRL3_ADDR);
|
||||
+ writel(PHY_CTRL4_VAL, phy->base + PHY_CTRL4_ADDR);
|
||||
+ writel(PHY_MISC_VAL, phy->base + PHY_MISC_ADDR);
|
||||
+ writel(PHY_IPG_VAL, phy->base + PHY_IPG_ADDR);
|
||||
+ msleep(10);
|
||||
+
|
||||
+ reset_control_deassert(phy->por_rst);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static struct phy_ops ipq4019_usb_hs_phy_ops = {
|
||||
+ .power_on = ipq4019_hs_phy_power_on,
|
||||
+ .power_off = ipq4019_hs_phy_power_off,
|
||||
+};
|
||||
+
|
||||
+static const struct of_device_id ipq4019_usb_phy_of_match[] = {
|
||||
+ { .compatible = "qcom,usb-hs-ipq4019-phy", .data = &ipq4019_usb_hs_phy_ops},
|
||||
+ { .compatible = "qcom,usb-ss-ipq4019-phy", .data = &ipq4019_usb_ss_phy_ops},
|
||||
+ { },
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, ipq4019_usb_phy_of_match);
|
||||
+
|
||||
+static int ipq4019_usb_phy_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ struct resource *res;
|
||||
+ struct phy_provider *phy_provider;
|
||||
+ struct ipq4019_usb_phy *phy;
|
||||
+ const struct of_device_id *match;
|
||||
+
|
||||
+ match = of_match_device(ipq4019_usb_phy_of_match, &pdev->dev);
|
||||
+ if (!match)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
|
||||
+ if (!phy)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ phy->dev = &pdev->dev;
|
||||
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
+ phy->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
+ if (IS_ERR(phy->base)) {
|
||||
+ dev_err(dev, "failed to remap register memory\n");
|
||||
+ return PTR_ERR(phy->base);
|
||||
+ }
|
||||
+
|
||||
+ phy->por_rst = devm_reset_control_get(phy->dev, "por_rst");
|
||||
+ if (IS_ERR(phy->por_rst)) {
|
||||
+ if (PTR_ERR(phy->por_rst) != -EPROBE_DEFER)
|
||||
+ dev_err(dev, "POR reset is missing\n");
|
||||
+ return PTR_ERR(phy->por_rst);
|
||||
+ }
|
||||
+
|
||||
+ phy->srif_rst = devm_reset_control_get_optional(phy->dev, "srif_rst");
|
||||
+ if (IS_ERR(phy->srif_rst))
|
||||
+ return PTR_ERR(phy->srif_rst);
|
||||
+
|
||||
+ phy->phy = devm_phy_create(dev, NULL, match->data);
|
||||
+ if (IS_ERR(phy->phy)) {
|
||||
+ dev_err(dev, "failed to create PHY\n");
|
||||
+ return PTR_ERR(phy->phy);
|
||||
+ }
|
||||
+ phy_set_drvdata(phy->phy, phy);
|
||||
+
|
||||
+ phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
|
||||
+
|
||||
+ return PTR_ERR_OR_ZERO(phy_provider);
|
||||
+}
|
||||
+
|
||||
+static struct platform_driver ipq4019_usb_phy_driver = {
|
||||
+ .probe = ipq4019_usb_phy_probe,
|
||||
+ .driver = {
|
||||
+ .of_match_table = ipq4019_usb_phy_of_match,
|
||||
+ .name = "ipq4019-usb-phy",
|
||||
+ }
|
||||
+};
|
||||
+module_platform_driver(ipq4019_usb_phy_driver);
|
||||
+
|
||||
+MODULE_DESCRIPTION("QCOM/IPQ4019 USB phy driver");
|
||||
+MODULE_AUTHOR("John Crispin <john@phrozen.org>");
|
||||
+MODULE_LICENSE("GPL v2");
|
||||
--- a/drivers/phy/qualcomm/Makefile
|
||||
+++ b/drivers/phy/qualcomm/Makefile
|
||||
@@ -1,5 +1,6 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
obj-$(CONFIG_PHY_QCOM_APQ8064_SATA) += phy-qcom-apq8064-sata.o
|
||||
+obj-$(CONFIG_PHY_QCOM_IPQ4019_USB) += phy-qcom-ipq4019-usb.o
|
||||
obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA) += phy-qcom-ipq806x-sata.o
|
||||
obj-$(CONFIG_PHY_QCOM_QMP) += phy-qcom-qmp.o
|
||||
obj-$(CONFIG_PHY_QCOM_QUSB2) += phy-qcom-qusb2.o
|
||||
@ -1,123 +0,0 @@
|
||||
From 1fc7d5523e21ed140fed43c4dde011a3b6d9ba08 Mon Sep 17 00:00:00 2001
|
||||
From: John Crispin <john@phrozen.org>
|
||||
Date: Tue, 24 Jul 2018 14:47:55 +0200
|
||||
Subject: [PATCH 3/3] qcom: ipq4019: add USB devicetree nodes
|
||||
|
||||
This patch makes USB work on the Dakota EVB.
|
||||
|
||||
Signed-off-by: John Crispin <john@phrozen.org>
|
||||
---
|
||||
arch/arm/boot/dts/qcom-ipq4019-ap.dk01.1.dtsi | 20 ++++++++
|
||||
arch/arm/boot/dts/qcom-ipq4019.dtsi | 74 +++++++++++++++++++++++++++
|
||||
2 files changed, 94 insertions(+)
|
||||
|
||||
--- a/arch/arm/boot/dts/qcom-ipq4019-ap.dk01.1.dtsi
|
||||
+++ b/arch/arm/boot/dts/qcom-ipq4019-ap.dk01.1.dtsi
|
||||
@@ -101,5 +101,25 @@
|
||||
wifi@a800000 {
|
||||
status = "ok";
|
||||
};
|
||||
+
|
||||
+ usb3_ss_phy: ssphy@9a000 {
|
||||
+ status = "ok";
|
||||
+ };
|
||||
+
|
||||
+ usb3_hs_phy: hsphy@a6000 {
|
||||
+ status = "ok";
|
||||
+ };
|
||||
+
|
||||
+ usb3: usb3@8af8800 {
|
||||
+ status = "ok";
|
||||
+ };
|
||||
+
|
||||
+ usb2_hs_phy: hsphy@a8000 {
|
||||
+ status = "ok";
|
||||
+ };
|
||||
+
|
||||
+ usb2: usb2@60f8800 {
|
||||
+ status = "ok";
|
||||
+ };
|
||||
};
|
||||
};
|
||||
--- a/arch/arm/boot/dts/qcom-ipq4019.dtsi
|
||||
+++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi
|
||||
@@ -414,5 +414,79 @@
|
||||
"legacy";
|
||||
status = "disabled";
|
||||
};
|
||||
+
|
||||
+ usb3_ss_phy: ssphy@9a000 {
|
||||
+ compatible = "qcom,usb-ss-ipq4019-phy";
|
||||
+ #phy-cells = <0>;
|
||||
+ reg = <0x9a000 0x800>;
|
||||
+ reg-names = "phy_base";
|
||||
+ resets = <&gcc USB3_UNIPHY_PHY_ARES>;
|
||||
+ reset-names = "por_rst";
|
||||
+ status = "disabled";
|
||||
+ };
|
||||
+
|
||||
+ usb3_hs_phy: hsphy@a6000 {
|
||||
+ compatible = "qcom,usb-hs-ipq4019-phy";
|
||||
+ #phy-cells = <0>;
|
||||
+ reg = <0xa6000 0x40>;
|
||||
+ reg-names = "phy_base";
|
||||
+ resets = <&gcc USB3_HSPHY_POR_ARES>, <&gcc USB3_HSPHY_S_ARES>;
|
||||
+ reset-names = "por_rst", "srif_rst";
|
||||
+ status = "disabled";
|
||||
+ };
|
||||
+
|
||||
+ usb3@8af8800 {
|
||||
+ compatible = "qcom,dwc3";
|
||||
+ reg = <0x8af8800 0x100>;
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <1>;
|
||||
+ clocks = <&gcc GCC_USB3_MASTER_CLK>,
|
||||
+ <&gcc GCC_USB3_SLEEP_CLK>,
|
||||
+ <&gcc GCC_USB3_MOCK_UTMI_CLK>;
|
||||
+ clock-names = "master", "sleep", "mock_utmi";
|
||||
+ ranges;
|
||||
+ status = "disabled";
|
||||
+
|
||||
+ dwc3@8a00000 {
|
||||
+ compatible = "snps,dwc3";
|
||||
+ reg = <0x8a00000 0xf8000>;
|
||||
+ interrupts = <GIC_SPI 132 IRQ_TYPE_LEVEL_HIGH>;
|
||||
+ phys = <&usb3_hs_phy>, <&usb3_ss_phy>;
|
||||
+ phy-names = "usb2-phy", "usb3-phy";
|
||||
+ dr_mode = "host";
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
+ usb2_hs_phy: hsphy@a8000 {
|
||||
+ compatible = "qcom,usb-hs-ipq4019-phy";
|
||||
+ #phy-cells = <0>;
|
||||
+ reg = <0xa8000 0x40>;
|
||||
+ reg-names = "phy_base";
|
||||
+ resets = <&gcc USB2_HSPHY_POR_ARES>, <&gcc USB2_HSPHY_S_ARES>;
|
||||
+ reset-names = "por_rst", "srif_rst";
|
||||
+ status = "disabled";
|
||||
+ };
|
||||
+
|
||||
+ usb2@60f8800 {
|
||||
+ compatible = "qcom,dwc3";
|
||||
+ reg = <0x60f8800 0x100>;
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <1>;
|
||||
+ clocks = <&gcc GCC_USB2_MASTER_CLK>,
|
||||
+ <&gcc GCC_USB2_SLEEP_CLK>,
|
||||
+ <&gcc GCC_USB2_MOCK_UTMI_CLK>;
|
||||
+ clock-names = "master", "sleep", "mock_utmi";
|
||||
+ ranges;
|
||||
+ status = "disabled";
|
||||
+
|
||||
+ dwc3@6000000 {
|
||||
+ compatible = "snps,dwc3";
|
||||
+ reg = <0x6000000 0xf8000>;
|
||||
+ interrupts = <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>;
|
||||
+ phys = <&usb2_hs_phy>;
|
||||
+ phy-names = "usb2-phy";
|
||||
+ dr_mode = "host";
|
||||
+ };
|
||||
+ };
|
||||
};
|
||||
};
|
||||
@ -1,278 +0,0 @@
|
||||
From 187519403273f0599c848d20eca9acce8b1807a5 Mon Sep 17 00:00:00 2001
|
||||
From: Sricharan R <sricharan@codeaurora.org>
|
||||
Date: Fri, 25 May 2018 11:41:12 +0530
|
||||
Subject: [PATCH] ARM: dts: ipq4019: Add a few peripheral nodes
|
||||
|
||||
Now with the driver updates for some peripherals being there,
|
||||
add i2c, spi, pcie, bam, qpic-nand, scm nodes to enhance the available
|
||||
peripheral support.
|
||||
|
||||
Reviewed-by: Abhishek Sahu <absahu@codeaurora.org>
|
||||
Signed-off-by: Sricharan R <sricharan@codeaurora.org>
|
||||
Signed-off-by: Andy Gross <andy.gross@linaro.org>
|
||||
---
|
||||
arch/arm/boot/dts/qcom-ipq4019-ap.dk01.1.dtsi | 2 +-
|
||||
arch/arm/boot/dts/qcom-ipq4019.dtsi | 156 ++++++++++++++++++++++++--
|
||||
2 files changed, 146 insertions(+), 12 deletions(-)
|
||||
|
||||
--- a/arch/arm/boot/dts/qcom-ipq4019-ap.dk01.1.dtsi
|
||||
+++ b/arch/arm/boot/dts/qcom-ipq4019-ap.dk01.1.dtsi
|
||||
@@ -61,7 +61,7 @@
|
||||
status = "ok";
|
||||
};
|
||||
|
||||
- spi_0: spi@78b5000 {
|
||||
+ spi@78b5000 {
|
||||
pinctrl-0 = <&spi_0_pins>;
|
||||
pinctrl-names = "default";
|
||||
status = "ok";
|
||||
--- a/arch/arm/boot/dts/qcom-ipq4019.dtsi
|
||||
+++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi
|
||||
@@ -24,8 +24,10 @@
|
||||
interrupt-parent = <&intc>;
|
||||
|
||||
aliases {
|
||||
- spi0 = &spi_0;
|
||||
- i2c0 = &i2c_0;
|
||||
+ spi0 = &blsp1_spi1;
|
||||
+ spi1 = &blsp1_spi2;
|
||||
+ i2c0 = &blsp1_i2c3;
|
||||
+ i2c1 = &blsp1_i2c4;
|
||||
};
|
||||
|
||||
cpus {
|
||||
@@ -136,6 +138,12 @@
|
||||
};
|
||||
};
|
||||
|
||||
+ firmware {
|
||||
+ scm {
|
||||
+ compatible = "qcom,scm-ipq4019";
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
timer {
|
||||
compatible = "arm,armv7-timer";
|
||||
interrupts = <1 2 0xf08>,
|
||||
@@ -181,13 +189,13 @@
|
||||
#gpio-cells = <2>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
- interrupts = <0 208 0>;
|
||||
+ interrupts = <GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
|
||||
blsp_dma: dma@7884000 {
|
||||
compatible = "qcom,bam-v1.7.0";
|
||||
reg = <0x07884000 0x23000>;
|
||||
- interrupts = <GIC_SPI 238 IRQ_TYPE_NONE>;
|
||||
+ interrupts = <GIC_SPI 238 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&gcc GCC_BLSP1_AHB_CLK>;
|
||||
clock-names = "bam_clk";
|
||||
#dma-cells = <1>;
|
||||
@@ -195,7 +203,7 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
- spi_0: spi@78b5000 {
|
||||
+ blsp1_spi1: spi@78b5000 { /* BLSP1 QUP1 */
|
||||
compatible = "qcom,spi-qup-v2.2.1";
|
||||
reg = <0x78b5000 0x600>;
|
||||
interrupts = <GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH>;
|
||||
@@ -204,10 +212,26 @@
|
||||
clock-names = "core", "iface";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
+ dmas = <&blsp_dma 5>, <&blsp_dma 4>;
|
||||
+ dma-names = "rx", "tx";
|
||||
+ status = "disabled";
|
||||
+ };
|
||||
+
|
||||
+ blsp1_spi2: spi@78b6000 { /* BLSP1 QUP2 */
|
||||
+ compatible = "qcom,spi-qup-v2.2.1";
|
||||
+ reg = <0x78b6000 0x600>;
|
||||
+ interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>;
|
||||
+ clocks = <&gcc GCC_BLSP1_QUP2_SPI_APPS_CLK>,
|
||||
+ <&gcc GCC_BLSP1_AHB_CLK>;
|
||||
+ clock-names = "core", "iface";
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
+ dmas = <&blsp_dma 7>, <&blsp_dma 6>;
|
||||
+ dma-names = "rx", "tx";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
- i2c_0: i2c@78b7000 {
|
||||
+ blsp1_i2c3: i2c@78b7000 { /* BLSP1 QUP3 */
|
||||
compatible = "qcom,i2c-qup-v2.2.1";
|
||||
reg = <0x78b7000 0x600>;
|
||||
interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
|
||||
@@ -216,14 +240,29 @@
|
||||
clock-names = "iface", "core";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
+ dmas = <&blsp_dma 9>, <&blsp_dma 8>;
|
||||
+ dma-names = "rx", "tx";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
+ blsp1_i2c4: i2c@78b8000 { /* BLSP1 QUP4 */
|
||||
+ compatible = "qcom,i2c-qup-v2.2.1";
|
||||
+ reg = <0x78b8000 0x600>;
|
||||
+ interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
|
||||
+ clocks = <&gcc GCC_BLSP1_AHB_CLK>,
|
||||
+ <&gcc GCC_BLSP1_QUP2_I2C_APPS_CLK>;
|
||||
+ clock-names = "iface", "core";
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
+ dmas = <&blsp_dma 11>, <&blsp_dma 10>;
|
||||
+ dma-names = "rx", "tx";
|
||||
+ status = "disabled";
|
||||
+ };
|
||||
|
||||
cryptobam: dma@8e04000 {
|
||||
compatible = "qcom,bam-v1.7.0";
|
||||
reg = <0x08e04000 0x20000>;
|
||||
- interrupts = <GIC_SPI 207 0>;
|
||||
+ interrupts = <GIC_SPI 207 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&gcc GCC_CRYPTO_AHB_CLK>;
|
||||
clock-names = "bam_clk";
|
||||
#dma-cells = <1>;
|
||||
@@ -297,7 +336,7 @@
|
||||
serial@78af000 {
|
||||
compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
|
||||
reg = <0x78af000 0x200>;
|
||||
- interrupts = <0 107 0>;
|
||||
+ interrupts = <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>;
|
||||
status = "disabled";
|
||||
clocks = <&gcc GCC_BLSP1_UART1_APPS_CLK>,
|
||||
<&gcc GCC_BLSP1_AHB_CLK>;
|
||||
@@ -309,7 +348,7 @@
|
||||
serial@78b0000 {
|
||||
compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
|
||||
reg = <0x78b0000 0x200>;
|
||||
- interrupts = <0 108 0>;
|
||||
+ interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
|
||||
status = "disabled";
|
||||
clocks = <&gcc GCC_BLSP1_UART2_APPS_CLK>,
|
||||
<&gcc GCC_BLSP1_AHB_CLK>;
|
||||
@@ -331,6 +370,101 @@
|
||||
reg = <0x4ab000 0x4>;
|
||||
};
|
||||
|
||||
+ pcie0: pci@40000000 {
|
||||
+ compatible = "qcom,pcie-ipq4019", "snps,dw-pcie";
|
||||
+ reg = <0x40000000 0xf1d
|
||||
+ 0x40000f20 0xa8
|
||||
+ 0x80000 0x2000
|
||||
+ 0x40100000 0x1000>;
|
||||
+ reg-names = "dbi", "elbi", "parf", "config";
|
||||
+ device_type = "pci";
|
||||
+ linux,pci-domain = <0>;
|
||||
+ bus-range = <0x00 0xff>;
|
||||
+ num-lanes = <1>;
|
||||
+ #address-cells = <3>;
|
||||
+ #size-cells = <2>;
|
||||
+
|
||||
+ ranges = <0x81000000 0 0x40200000 0x40200000 0 0x00100000
|
||||
+ 0x82000000 0 0x48000000 0x48000000 0 0x10000000>;
|
||||
+
|
||||
+ interrupts = <GIC_SPI 141 IRQ_TYPE_EDGE_RISING>;
|
||||
+ interrupt-names = "msi";
|
||||
+ #interrupt-cells = <1>;
|
||||
+ interrupt-map-mask = <0 0 0 0x7>;
|
||||
+ interrupt-map = <0 0 0 1 &intc 0 142 IRQ_TYPE_LEVEL_HIGH>, /* int_a */
|
||||
+ <0 0 0 2 &intc 0 143 IRQ_TYPE_LEVEL_HIGH>, /* int_b */
|
||||
+ <0 0 0 3 &intc 0 144 IRQ_TYPE_LEVEL_HIGH>, /* int_c */
|
||||
+ <0 0 0 4 &intc 0 145 IRQ_TYPE_LEVEL_HIGH>; /* int_d */
|
||||
+ clocks = <&gcc GCC_PCIE_AHB_CLK>,
|
||||
+ <&gcc GCC_PCIE_AXI_M_CLK>,
|
||||
+ <&gcc GCC_PCIE_AXI_S_CLK>;
|
||||
+ clock-names = "aux",
|
||||
+ "master_bus",
|
||||
+ "slave_bus";
|
||||
+
|
||||
+ resets = <&gcc PCIE_AXI_M_ARES>,
|
||||
+ <&gcc PCIE_AXI_S_ARES>,
|
||||
+ <&gcc PCIE_PIPE_ARES>,
|
||||
+ <&gcc PCIE_AXI_M_VMIDMT_ARES>,
|
||||
+ <&gcc PCIE_AXI_S_XPU_ARES>,
|
||||
+ <&gcc PCIE_PARF_XPU_ARES>,
|
||||
+ <&gcc PCIE_PHY_ARES>,
|
||||
+ <&gcc PCIE_AXI_M_STICKY_ARES>,
|
||||
+ <&gcc PCIE_PIPE_STICKY_ARES>,
|
||||
+ <&gcc PCIE_PWR_ARES>,
|
||||
+ <&gcc PCIE_AHB_ARES>,
|
||||
+ <&gcc PCIE_PHY_AHB_ARES>;
|
||||
+ reset-names = "axi_m",
|
||||
+ "axi_s",
|
||||
+ "pipe",
|
||||
+ "axi_m_vmid",
|
||||
+ "axi_s_xpu",
|
||||
+ "parf",
|
||||
+ "phy",
|
||||
+ "axi_m_sticky",
|
||||
+ "pipe_sticky",
|
||||
+ "pwr",
|
||||
+ "ahb",
|
||||
+ "phy_ahb";
|
||||
+
|
||||
+ status = "disabled";
|
||||
+ };
|
||||
+
|
||||
+ qpic_bam: dma@7984000 {
|
||||
+ compatible = "qcom,bam-v1.7.0";
|
||||
+ reg = <0x7984000 0x1a000>;
|
||||
+ interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;
|
||||
+ clocks = <&gcc GCC_QPIC_CLK>;
|
||||
+ clock-names = "bam_clk";
|
||||
+ #dma-cells = <1>;
|
||||
+ qcom,ee = <0>;
|
||||
+ status = "disabled";
|
||||
+ };
|
||||
+
|
||||
+ nand: qpic-nand@79b0000 {
|
||||
+ compatible = "qcom,ipq4019-nand";
|
||||
+ reg = <0x79b0000 0x1000>;
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
+ clocks = <&gcc GCC_QPIC_CLK>,
|
||||
+ <&gcc GCC_QPIC_AHB_CLK>;
|
||||
+ clock-names = "core", "aon";
|
||||
+
|
||||
+ dmas = <&qpic_bam 0>,
|
||||
+ <&qpic_bam 1>,
|
||||
+ <&qpic_bam 2>;
|
||||
+ dma-names = "tx", "rx", "cmd";
|
||||
+ status = "disabled";
|
||||
+
|
||||
+ nand@0 {
|
||||
+ reg = <0>;
|
||||
+
|
||||
+ nand-ecc-strength = <4>;
|
||||
+ nand-ecc-step-size = <512>;
|
||||
+ nand-bus-width = <8>;
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
wifi0: wifi@a000000 {
|
||||
compatible = "qcom,ipq4019-wifi";
|
||||
reg = <0xa000000 0x200000>;
|
||||
@@ -364,7 +498,7 @@
|
||||
<GIC_SPI 45 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 46 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 47 IRQ_TYPE_EDGE_RISING>,
|
||||
- <GIC_SPI 168 IRQ_TYPE_NONE>;
|
||||
+ <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "msi0", "msi1", "msi2", "msi3",
|
||||
"msi4", "msi5", "msi6", "msi7",
|
||||
"msi8", "msi9", "msi10", "msi11",
|
||||
@@ -406,7 +540,7 @@
|
||||
<GIC_SPI 61 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 62 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 63 IRQ_TYPE_EDGE_RISING>,
|
||||
- <GIC_SPI 169 IRQ_TYPE_NONE>;
|
||||
+ <GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "msi0", "msi1", "msi2", "msi3",
|
||||
"msi4", "msi5", "msi6", "msi7",
|
||||
"msi8", "msi9", "msi10", "msi11",
|
||||
@ -1,23 +0,0 @@
|
||||
From 561a7e69d2811f236266ff9222a1e683ebf8b9e0 Mon Sep 17 00:00:00 2001
|
||||
From: Mathias Kresin <dev@kresin.me>
|
||||
Date: Thu, 1 Mar 2018 20:50:29 +0100
|
||||
Subject: [PATCH] ARM: dts: ipq4019: fix PCI range
|
||||
|
||||
The PCI range is invalid and PCI attached devices doen't work.
|
||||
|
||||
Signed-off-by: Mathias Kresin <dev@kresin.me>
|
||||
---
|
||||
arch/arm/boot/dts/qcom-ipq4019.dtsi | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/arch/arm/boot/dts/qcom-ipq4019.dtsi
|
||||
+++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi
|
||||
@@ -385,7 +385,7 @@
|
||||
#size-cells = <2>;
|
||||
|
||||
ranges = <0x81000000 0 0x40200000 0x40200000 0 0x00100000
|
||||
- 0x82000000 0 0x48000000 0x48000000 0 0x10000000>;
|
||||
+ 0x82000000 0 0x40300000 0x40300000 0 0x400000>;
|
||||
|
||||
interrupts = <GIC_SPI 141 IRQ_TYPE_EDGE_RISING>;
|
||||
interrupt-names = "msi";
|
||||
@ -1,71 +0,0 @@
|
||||
From: Christian Lamparter <chunkeey@gmail.com>
|
||||
Date: Thu, 12 Apr 2018 21:01:38 +0200
|
||||
Subject: [PATCH] pinctrl: msm: fix gpio-hog related boot issues
|
||||
|
||||
Sven Eckelmann reported an issue with the current IPQ4019 pinctrl.
|
||||
Setting up any gpio-hog in the device-tree for his device would
|
||||
"kill the bootup completely":
|
||||
|
||||
| [ 0.477838] msm_serial 78af000.serial: could not find pctldev for node /soc/pinctrl@1000000/serial_pinmux, deferring probe
|
||||
| [ 0.499828] spi_qup 78b5000.spi: could not find pctldev for node /soc/pinctrl@1000000/spi_0_pinmux, deferring probe
|
||||
| [ 1.298883] requesting hog GPIO enable USB2 power (chip 1000000.pinctrl, offset 58) failed, -517
|
||||
| [ 1.299609] gpiochip_add_data: GPIOs 0..99 (1000000.pinctrl) failed to register
|
||||
| [ 1.308589] ipq4019-pinctrl 1000000.pinctrl: Failed register gpiochip
|
||||
| [ 1.316586] msm_serial 78af000.serial: could not find pctldev for node /soc/pinctrl@1000000/serial_pinmux, deferring probe
|
||||
| [ 1.322415] spi_qup 78b5000.spi: could not find pctldev for node /soc/pinctrl@1000000/spi_0_pinmux, deferri
|
||||
|
||||
This was also verified on a RT-AC58U (IPQ4018) which would
|
||||
no longer boot, if a gpio-hog was specified. (Tried forcing
|
||||
the USB LED PIN (GPIO0) to high.).
|
||||
|
||||
The problem is that Pinctrl+GPIO registration is currently
|
||||
peformed in the following order in pinctrl-msm.c:
|
||||
1. pinctrl_register()
|
||||
2. gpiochip_add()
|
||||
3. gpiochip_add_pin_range()
|
||||
|
||||
The actual error code -517 == -EPROBE_DEFER is coming from
|
||||
pinctrl_get_device_gpio_range(), which is called through:
|
||||
gpiochip_add
|
||||
of_gpiochip_add
|
||||
of_gpiochip_scan_gpios
|
||||
gpiod_hog
|
||||
gpiochip_request_own_desc
|
||||
__gpiod_request
|
||||
chip->request
|
||||
gpiochip_generic_request
|
||||
pinctrl_gpio_request
|
||||
pinctrl_get_device_gpio_range
|
||||
|
||||
pinctrl_get_device_gpio_range() is unable to find any valid
|
||||
pin ranges, since nothing has been added to the pinctrldev_list yet.
|
||||
so the range can't be found, and the operation fails with -EPROBE_DEFER.
|
||||
|
||||
This patch fixes the issue by adding the "gpio-ranges" property to
|
||||
the pinctrl device node of all upstream Qcom SoC. The pin ranges are
|
||||
then added by the gpio core.
|
||||
|
||||
In order to remain compatible with older, existing DTs (and ACPI)
|
||||
a check for the "gpio-ranges" property has been added to
|
||||
msm_gpio_init(). This prevents the driver of adding the same entry
|
||||
to the pinctrldev_list twice.
|
||||
|
||||
Reported-by: Sven Eckelmann <sven.eckelmann@openmesh.com>
|
||||
Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
|
||||
|
||||
Origin: other, https://patchwork.kernel.org/patch/10339127/
|
||||
---
|
||||
arch/arm/boot/dts/qcom-ipq4019.dtsi | 1 +
|
||||
drivers/pinctrl/qcom/pinctrl-msm.c | 23 ++++++++++++++++++-----
|
||||
14 files changed, 32 insertions(+), 6 deletions(-)
|
||||
|
||||
--- a/arch/arm/boot/dts/qcom-ipq4019.dtsi
|
||||
+++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi
|
||||
@@ -186,6 +186,7 @@
|
||||
compatible = "qcom,ipq4019-pinctrl";
|
||||
reg = <0x01000000 0x300000>;
|
||||
gpio-controller;
|
||||
+ gpio-ranges = <&tlmm 0 0 100>;
|
||||
#gpio-cells = <2>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
@ -1,115 +0,0 @@
|
||||
From f2b87dc1028b710ec8ce25808b9d21f92b376184 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Lamparter <chunkeey@googlemail.com>
|
||||
Date: Sun, 11 Mar 2018 14:41:31 +0100
|
||||
Subject: [PATCH 2/2] clk: fix apss cpu overclocking
|
||||
|
||||
There's an interaction issue between the clk changes:"
|
||||
clk: qcom: ipq4019: Add the apss cpu pll divider clock node
|
||||
clk: qcom: ipq4019: remove fixed clocks and add pll clocks
|
||||
" and the cpufreq-dt.
|
||||
|
||||
cpufreq-dt is now spamming the kernel-log with the following:
|
||||
|
||||
[ 1099.190658] cpu cpu0: dev_pm_opp_set_rate: failed to find current OPP
|
||||
for freq 761142857 (-34)
|
||||
|
||||
This only happens on certain devices like the Compex WPJ428
|
||||
and AVM FritzBox!4040. However, other devices like the Asus
|
||||
RT-AC58U and Meraki MR33 work just fine.
|
||||
|
||||
The issue stem from the fact that all higher CPU-Clocks
|
||||
are achieved by switching the clock-parent to the P_DDRPLLAPSS
|
||||
(ddrpllapss). Which is set by Qualcomm's proprietary bootcode
|
||||
as part of the DDR calibration.
|
||||
|
||||
For example, the FB4040 uses 256 MiB Nanya NT5CC128M16IP clocked
|
||||
at round 533 MHz (ddrpllsdcc = 190285714 Hz).
|
||||
|
||||
whereas the 128 MiB Nanya NT5CC64M16GP-DI in the ASUS RT-AC58U is
|
||||
clocked at a slightly higher 537 MHz ( ddrpllsdcc = 192000000 Hz).
|
||||
|
||||
This patch attempts to fix the issue by modifying
|
||||
clk_cpu_div_round_rate(), clk_cpu_div_set_rate(), clk_cpu_div_recalc_rate()
|
||||
to use a new qcom_find_freq_close() function, which returns the closest
|
||||
matching frequency, instead of the next higher. This way, the SoC in
|
||||
the FB4040 (with its max clock speed of 710.4 MHz) will no longer
|
||||
try to overclock to 761 MHz.
|
||||
|
||||
Fixes: d83dcacea18 ("clk: qcom: ipq4019: Add the apss cpu pll divider clock node")
|
||||
Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
|
||||
Signed-off-by: John Crispin <john@phrozen.org>
|
||||
---
|
||||
drivers/clk/qcom/gcc-ipq4019.c | 34 +++++++++++++++++++++++++++++++---
|
||||
1 file changed, 31 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/drivers/clk/qcom/gcc-ipq4019.c
|
||||
+++ b/drivers/clk/qcom/gcc-ipq4019.c
|
||||
@@ -1253,6 +1253,29 @@ static const struct clk_fepll_vco gcc_fe
|
||||
.reg = 0x2f020,
|
||||
};
|
||||
|
||||
+
|
||||
+const struct freq_tbl *qcom_find_freq_close(const struct freq_tbl *f,
|
||||
+ unsigned long rate)
|
||||
+{
|
||||
+ const struct freq_tbl *last = NULL;
|
||||
+
|
||||
+ for ( ; f->freq; f++) {
|
||||
+ if (rate == f->freq)
|
||||
+ return f;
|
||||
+
|
||||
+ if (f->freq > rate) {
|
||||
+ if (!last ||
|
||||
+ (f->freq - rate) < (rate - last->freq))
|
||||
+ return f;
|
||||
+ else
|
||||
+ return last;
|
||||
+ }
|
||||
+ last = f;
|
||||
+ }
|
||||
+
|
||||
+ return last;
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* Round rate function for APSS CPU PLL Clock divider.
|
||||
* It looks up the frequency table and returns the next higher frequency
|
||||
@@ -1265,7 +1288,7 @@ static long clk_cpu_div_round_rate(struc
|
||||
struct clk_hw *p_hw;
|
||||
const struct freq_tbl *f;
|
||||
|
||||
- f = qcom_find_freq(pll->freq_tbl, rate);
|
||||
+ f = qcom_find_freq_close(pll->freq_tbl, rate);
|
||||
if (!f)
|
||||
return -EINVAL;
|
||||
|
||||
@@ -1288,7 +1311,7 @@ static int clk_cpu_div_set_rate(struct c
|
||||
u32 mask;
|
||||
int ret;
|
||||
|
||||
- f = qcom_find_freq(pll->freq_tbl, rate);
|
||||
+ f = qcom_find_freq_close(pll->freq_tbl, rate);
|
||||
if (!f)
|
||||
return -EINVAL;
|
||||
|
||||
@@ -1315,6 +1338,7 @@ static unsigned long
|
||||
clk_cpu_div_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
+ const struct freq_tbl *f;
|
||||
struct clk_fepll *pll = to_clk_fepll(hw);
|
||||
u32 cdiv, pre_div;
|
||||
u64 rate;
|
||||
@@ -1335,7 +1359,11 @@ clk_cpu_div_recalc_rate(struct clk_hw *h
|
||||
rate = clk_fepll_vco_calc_rate(pll, parent_rate) * 2;
|
||||
do_div(rate, pre_div);
|
||||
|
||||
- return rate;
|
||||
+ f = qcom_find_freq_close(pll->freq_tbl, rate);
|
||||
+ if (!f)
|
||||
+ return rate;
|
||||
+
|
||||
+ return f->freq;
|
||||
};
|
||||
|
||||
static const struct clk_ops clk_regmap_cpu_div_ops = {
|
||||
@ -1,88 +0,0 @@
|
||||
From fc566294610fa49e9d8c31c4ecc9c82f49b11f59 Mon Sep 17 00:00:00 2001
|
||||
From: Sven Eckelmann <sven.eckelmann@openmesh.com>
|
||||
Date: Wed, 18 Apr 2018 09:10:44 +0200
|
||||
Subject: [PATCH] ARM: dts: ipq4019: Add TZ and SMEM reserved regions
|
||||
|
||||
The QSEE (trustzone) is started on IPQ4019 before Linux is started.
|
||||
According to QCA, it is placed in in the the memory region
|
||||
0x87e80000-0x88000000 and must not be accessed directly. There is an
|
||||
additional memory region 0x87e00000-0x87E80000 smem which which can be used
|
||||
for communication with the TZ. The driver for the latter is not yet ready
|
||||
but it is still not allowed to use this memory region like any other
|
||||
memory region.
|
||||
|
||||
Not reserving this memory region either leads to kernel crashes, kernel
|
||||
hangs (often during the boot) or bus errors for userspace programs. The
|
||||
latter happens when a program is using a memory region which is mapped to
|
||||
these physical memory regions.
|
||||
|
||||
[ 571.758058] Unhandled fault: imprecise external abort (0xc06) at 0x01715ff8
|
||||
[ 571.758099] pgd = cebec000
|
||||
[ 571.763826] [01715ff8] *pgd=8e7fa835, *pte=87e7f75f, *ppte=87e7fc7f
|
||||
Bus error
|
||||
|
||||
Signed-off-by: Sven Eckelmann <sven.eckelmann@openmesh.com>
|
||||
|
||||
Forwarded: https://patchwork.kernel.org/patch/10347459/
|
||||
---
|
||||
Cc: Sricharan Ramabadhran <srichara@qti.qualcomm.com>
|
||||
Cc: Senthilkumar N L <snlakshm@qti.qualcomm.com>
|
||||
|
||||
There are additional memory regions which have to be initialized first by
|
||||
Linux. So they are currently not used. We were told by QCA that the
|
||||
features QSDK uses them for are:
|
||||
|
||||
* crash dump feature
|
||||
- a couple of regions used when 'qca,scm_restart_reason' dt node has the
|
||||
value 'dload_status' not set to 1
|
||||
+ apps_bl <0x87000000 0x400000>
|
||||
+ sbl <0x87400000 0x100000>
|
||||
+ cnss_debug <0x87400000 0x100000>
|
||||
+ cpu_context_dump <0x87b00000 0x080000>
|
||||
- required driver not available in Linux
|
||||
- safe to remove
|
||||
* QSEE app execution
|
||||
- region tz_apps <0x87b80000 0x280000>
|
||||
- required driver not available in Linux
|
||||
- safe to remove
|
||||
* communication with TZ/QSEE
|
||||
- region smem <0x87b80000 0x280000>
|
||||
- driver changes not yet upstreamed
|
||||
- must not be removed because any access can crash kernel/program
|
||||
* trustzone (QSEE) private memory
|
||||
- region tz <0x87e80000 0x180000>
|
||||
- must not be removed because any access can crash kernel/program
|
||||
|
||||
The problem with the missing regions was reported in 2016 [1]. So maybe
|
||||
this change qualifies for a stable@vger.kernel.org submission.
|
||||
|
||||
[1] https://www.spinics.net/lists/linux-arm-msm/msg21536.html
|
||||
---
|
||||
arch/arm/boot/dts/qcom-ipq4019.dtsi | 16 ++++++++++++++++
|
||||
1 file changed, 16 insertions(+)
|
||||
|
||||
--- a/arch/arm/boot/dts/qcom-ipq4019.dtsi
|
||||
+++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi
|
||||
@@ -23,6 +23,22 @@
|
||||
compatible = "qcom,ipq4019";
|
||||
interrupt-parent = <&intc>;
|
||||
|
||||
+ reserved-memory {
|
||||
+ #address-cells = <0x1>;
|
||||
+ #size-cells = <0x1>;
|
||||
+ ranges;
|
||||
+
|
||||
+ smem_region: smem@87e00000 {
|
||||
+ reg = <0x87e00000 0x080000>;
|
||||
+ no-map;
|
||||
+ };
|
||||
+
|
||||
+ tz@87e80000 {
|
||||
+ reg = <0x87e80000 0x180000>;
|
||||
+ no-map;
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
aliases {
|
||||
spi0 = &blsp1_spi1;
|
||||
spi1 = &blsp1_spi2;
|
||||
@ -1,38 +0,0 @@
|
||||
From 07b6d0cdbbda8c917480eceaec668f09e4cf24a5 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Lamparter <chunkeey@gmail.com>
|
||||
Date: Mon, 14 Nov 2016 23:49:22 +0100
|
||||
Subject: [PATCH] mtd: nand: add Winbond manufacturer and chip
|
||||
|
||||
This patch adds the W25N01GV NAND to the table of
|
||||
known devices. Without this patch the device gets detected:
|
||||
|
||||
nand: device found, Manufacturer ID: 0xef, Chip ID: 0xaa
|
||||
nand: Unknown NAND 256MiB 1,8V 8-bit
|
||||
nand: 256 MiB, SLC, erase size: 64 KiB, page size: 1024, OOB size : 16
|
||||
|
||||
Whereas the u-boot identifies it as:
|
||||
spi_nand: spi_nand_flash_probe SF NAND ID 00:ef:aa:21
|
||||
SF: Detected W25N01GV with page size 2 KiB, total 128 MiB
|
||||
|
||||
Due to the page size discrepancy, it's impossible to attach
|
||||
ubi volumes on the device.
|
||||
|
||||
Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
|
||||
---
|
||||
drivers/mtd/nand/nand_ids.c | 4 ++++
|
||||
include/linux/mtd/nand.h | 1 +
|
||||
2 files changed, 5 insertions(+)
|
||||
|
||||
--- a/drivers/mtd/nand/nand_ids.c
|
||||
+++ b/drivers/mtd/nand/nand_ids.c
|
||||
@@ -54,6 +54,10 @@ struct nand_flash_dev nand_flash_ids[] =
|
||||
{ .id = {0xad, 0xde, 0x94, 0xda, 0x74, 0xc4} },
|
||||
SZ_8K, SZ_8K, SZ_2M, NAND_NEED_SCRAMBLING, 6, 640,
|
||||
NAND_ECC_INFO(40, SZ_1K), 4 },
|
||||
+ {"W25N01GV 1G 3.3V 8-bit",
|
||||
+ { .id = {0xef, 0xaa} },
|
||||
+ SZ_2K, SZ_128, SZ_128K, NAND_NO_SUBPAGE_WRITE,
|
||||
+ 2, 64, NAND_ECC_INFO(1, SZ_512) },
|
||||
|
||||
LEGACY_ID_NAND("NAND 4MiB 5V 8-bit", 0x6B, 4, SZ_8K, SP_OPTIONS),
|
||||
LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE3, 4, SZ_8K, SP_OPTIONS),
|
||||
@ -1,45 +0,0 @@
|
||||
From c696a020193e7f96ead97b6b19a2bcd929b299d3 Mon Sep 17 00:00:00 2001
|
||||
From: Sricharan R <sricharan@codeaurora.org>
|
||||
Date: Fri, 25 May 2018 11:41:11 +0530
|
||||
Subject: [PATCH] ARM: dts: ipq4019: Add a default chosen node
|
||||
|
||||
Add a 'chosen' node to select the serial console.
|
||||
This is needed when bootloaders do not pass the
|
||||
'console=' bootargs.
|
||||
|
||||
Acked-by: Bjorn Andersson <bjorn.andersson@linaro.org>
|
||||
Signed-off-by: Sricharan R <sricharan@codeaurora.org>
|
||||
Signed-off-by: Andy Gross <andy.gross@linaro.org>
|
||||
---
|
||||
arch/arm/boot/dts/qcom-ipq4019-ap.dk01.1.dtsi | 8 ++++++++
|
||||
arch/arm/boot/dts/qcom-ipq4019.dtsi | 2 +-
|
||||
2 files changed, 9 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/arch/arm/boot/dts/qcom-ipq4019-ap.dk01.1.dtsi
|
||||
+++ b/arch/arm/boot/dts/qcom-ipq4019-ap.dk01.1.dtsi
|
||||
@@ -20,6 +20,14 @@
|
||||
model = "Qualcomm Technologies, Inc. IPQ4019/AP-DK01.1";
|
||||
compatible = "qcom,ipq4019";
|
||||
|
||||
+ aliases {
|
||||
+ serial0 = &blsp1_uart1;
|
||||
+ };
|
||||
+
|
||||
+ chosen {
|
||||
+ stdout-path = "serial0:115200n8";
|
||||
+ };
|
||||
+
|
||||
soc {
|
||||
rng@22000 {
|
||||
status = "ok";
|
||||
--- a/arch/arm/boot/dts/qcom-ipq4019.dtsi
|
||||
+++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi
|
||||
@@ -350,7 +350,7 @@
|
||||
regulator;
|
||||
};
|
||||
|
||||
- serial@78af000 {
|
||||
+ blsp1_uart1: serial@78af000 {
|
||||
compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
|
||||
reg = <0x78af000 0x200>;
|
||||
interrupts = <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>;
|
||||
@ -1,13 +0,0 @@
|
||||
--- a/drivers/mtd/nand/nand_ids.c
|
||||
+++ b/drivers/mtd/nand/nand_ids.c
|
||||
@@ -54,6 +54,10 @@ struct nand_flash_dev nand_flash_ids[] =
|
||||
{ .id = {0xad, 0xde, 0x94, 0xda, 0x74, 0xc4} },
|
||||
SZ_8K, SZ_8K, SZ_2M, NAND_NEED_SCRAMBLING, 6, 640,
|
||||
NAND_ECC_INFO(40, SZ_1K), 4 },
|
||||
+ {"MX35LF1GE4AB 1G 3.3V 8-bit",
|
||||
+ { .id = {0xc2, 0x12} },
|
||||
+ SZ_2K, SZ_128, SZ_128K, NAND_NO_SUBPAGE_WRITE,
|
||||
+ 2, 64, NAND_ECC_INFO(4, SZ_512) },
|
||||
{"W25N01GV 1G 3.3V 8-bit",
|
||||
{ .id = {0xef, 0xaa} },
|
||||
SZ_2K, SZ_128, SZ_128K, NAND_NO_SUBPAGE_WRITE,
|
||||
@ -1,42 +0,0 @@
|
||||
From: Christian Lamparter <chunkeey@gmail.com>
|
||||
Date: Mon, 25 Feb 2019 20:14:19 +0100
|
||||
Subject: [PATCH] ARM: dts: qcom: ipq4019: enlarge PCIe BAR range
|
||||
|
||||
David Bauer reported that the VDSL modem (attached via PCIe)
|
||||
on his AVM Fritz!Box 7530 was complaining about not having
|
||||
enough space in the BAR. A closer inspection of the old
|
||||
qcom-ipq40xx.dtsi pulled from the GL-iNet repository listed:
|
||||
|
||||
| qcom,pcie@80000 {
|
||||
| compatible = "qcom,msm_pcie";
|
||||
| reg = <0x80000 0x2000>,
|
||||
| <0x99000 0x800>,
|
||||
| <0x40000000 0xf1d>,
|
||||
| <0x40000f20 0xa8>,
|
||||
| <0x40100000 0x1000>,
|
||||
| <0x40200000 0x100000>,
|
||||
| <0x40300000 0xd00000>;
|
||||
| reg-names = "parf", "phy", "dm_core", "elbi",
|
||||
| "conf", "io", "bars";
|
||||
|
||||
Matching the reg-names with the listed reg leads to
|
||||
<0xd00000> as the size for the "bars".
|
||||
|
||||
BugLink: https://www.mail-archive.com/openwrt-devel@lists.openwrt.org/msg45212.html
|
||||
Reported-by: David Bauer <mail@david-bauer.net>
|
||||
Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
|
||||
---
|
||||
|
||||
--- a/arch/arm/boot/dts/qcom-ipq4019.dtsi
|
||||
+++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi
|
||||
@@ -401,8 +401,8 @@
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
|
||||
- ranges = <0x81000000 0 0x40200000 0x40200000 0 0x00100000
|
||||
- 0x82000000 0 0x40300000 0x40300000 0 0x400000>;
|
||||
+ ranges = <0x81000000 0 0x40200000 0x40200000 0 0x00100000>,
|
||||
+ <0x82000000 0 0x40300000 0x40300000 0 0x00d00000>;
|
||||
|
||||
interrupts = <GIC_SPI 141 IRQ_TYPE_EDGE_RISING>;
|
||||
interrupt-names = "msi";
|
||||
@ -1,32 +0,0 @@
|
||||
From: Niklas Cassel <niklas.cassel@linaro.org>
|
||||
Subject: [PATCH] ARM: dts: qcom: ipq4019: Fix MSI IRQ type
|
||||
Date: Thu, 24 Jan 2019 14:00:47 +0100
|
||||
|
||||
The databook clearly states that the MSI IRQ (msi_ctrl_int) is a level
|
||||
triggered interrupt.
|
||||
|
||||
The msi_ctrl_int will be high for as long as any MSI status bit is set,
|
||||
thus the IRQ type should be set to IRQ_TYPE_LEVEL_HIGH, causing the
|
||||
IRQ handler to keep getting called, as long as any MSI status bit is set.
|
||||
|
||||
A git grep shows that ipq4019 is the only SoC using snps,dw-pcie that has
|
||||
configured this IRQ incorrectly.
|
||||
|
||||
Not having the correct IRQ type defined will cause us to lose interrupts,
|
||||
which in turn causes timeouts in the PCIe endpoint drivers.
|
||||
|
||||
Signed-off-by: Niklas Cassel <niklas.cassel@linaro.org>
|
||||
Reviewed-by: Bjorn Andersson <bjorn.andersson@linaro.org>
|
||||
---
|
||||
|
||||
--- a/arch/arm/boot/dts/qcom-ipq4019.dtsi
|
||||
+++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi
|
||||
@@ -404,7 +404,7 @@
|
||||
ranges = <0x81000000 0 0x40200000 0x40200000 0 0x00100000>,
|
||||
<0x82000000 0 0x40300000 0x40300000 0 0x00d00000>;
|
||||
|
||||
- interrupts = <GIC_SPI 141 IRQ_TYPE_EDGE_RISING>;
|
||||
+ interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "msi";
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-map-mask = <0 0 0 0x7>;
|
||||
@ -1,36 +0,0 @@
|
||||
From 0668bc44a42672626666e4f66aa1f2c22528e8a5 Mon Sep 17 00:00:00 2001
|
||||
From: Abhishek Sahu <absahu@codeaurora.org>
|
||||
Date: Mon, 12 Mar 2018 18:44:50 +0530
|
||||
Subject: [PATCH 01/13] i2c: qup: fix copyrights and update to SPDX identifier
|
||||
|
||||
The file has been updated from 2016 to 2018 so fixed the
|
||||
copyright years.
|
||||
|
||||
Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
|
||||
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
|
||||
---
|
||||
drivers/i2c/busses/i2c-qup.c | 13 ++-----------
|
||||
1 file changed, 2 insertions(+), 11 deletions(-)
|
||||
|
||||
--- a/drivers/i2c/busses/i2c-qup.c
|
||||
+++ b/drivers/i2c/busses/i2c-qup.c
|
||||
@@ -1,17 +1,8 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
- * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
|
||||
+ * Copyright (c) 2009-2013, 2016-2018, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2014, Sony Mobile Communications AB.
|
||||
*
|
||||
- *
|
||||
- * This program is free software; you can redistribute it and/or modify
|
||||
- * it under the terms of the GNU General Public License version 2 and
|
||||
- * only version 2 as published by the Free Software Foundation.
|
||||
- *
|
||||
- * This program is distributed in the hope that it will be useful,
|
||||
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
- * GNU General Public License for more details.
|
||||
- *
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
@ -1,76 +0,0 @@
|
||||
From eb422b539c1f39faf576826b54be93e84d9cb32a Mon Sep 17 00:00:00 2001
|
||||
From: Abhishek Sahu <absahu@codeaurora.org>
|
||||
Date: Mon, 12 Mar 2018 18:44:52 +0530
|
||||
Subject: [PATCH 03/13] i2c: qup: minor code reorganization for use_dma
|
||||
|
||||
1. Assigns use_dma in qup_dev structure itself which will
|
||||
help in subsequent patches to determine the mode in IRQ handler.
|
||||
2. Does minor code reorganization for loops to reduce the
|
||||
unnecessary comparison and assignment.
|
||||
|
||||
Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
|
||||
Reviewed-by: Austin Christ <austinwc@codeaurora.org>
|
||||
Reviewed-by: Andy Gross <andy.gross@linaro.org>
|
||||
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
|
||||
---
|
||||
drivers/i2c/busses/i2c-qup.c | 19 +++++++++++--------
|
||||
1 file changed, 11 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/drivers/i2c/busses/i2c-qup.c
|
||||
+++ b/drivers/i2c/busses/i2c-qup.c
|
||||
@@ -181,6 +181,8 @@ struct qup_i2c_dev {
|
||||
|
||||
/* dma parameters */
|
||||
bool is_dma;
|
||||
+ /* To check if the current transfer is using DMA */
|
||||
+ bool use_dma;
|
||||
struct dma_pool *dpool;
|
||||
struct qup_i2c_tag start_tag;
|
||||
struct qup_i2c_bam brx;
|
||||
@@ -1288,7 +1290,7 @@ static int qup_i2c_xfer_v2(struct i2c_ad
|
||||
int num)
|
||||
{
|
||||
struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
|
||||
- int ret, len, idx = 0, use_dma = 0;
|
||||
+ int ret, len, idx = 0;
|
||||
|
||||
qup->bus_err = 0;
|
||||
qup->qup_err = 0;
|
||||
@@ -1317,13 +1319,12 @@ static int qup_i2c_xfer_v2(struct i2c_ad
|
||||
len = (msgs[idx].len > qup->out_fifo_sz) ||
|
||||
(msgs[idx].len > qup->in_fifo_sz);
|
||||
|
||||
- if ((!is_vmalloc_addr(msgs[idx].buf)) && len) {
|
||||
- use_dma = 1;
|
||||
- } else {
|
||||
- use_dma = 0;
|
||||
+ if (is_vmalloc_addr(msgs[idx].buf) || !len)
|
||||
break;
|
||||
- }
|
||||
}
|
||||
+
|
||||
+ if (idx == num)
|
||||
+ qup->use_dma = true;
|
||||
}
|
||||
|
||||
idx = 0;
|
||||
@@ -1347,15 +1348,17 @@ static int qup_i2c_xfer_v2(struct i2c_ad
|
||||
|
||||
reinit_completion(&qup->xfer);
|
||||
|
||||
- if (use_dma) {
|
||||
+ if (qup->use_dma) {
|
||||
ret = qup_i2c_bam_xfer(adap, &msgs[idx], num);
|
||||
+ qup->use_dma = false;
|
||||
+ break;
|
||||
} else {
|
||||
if (msgs[idx].flags & I2C_M_RD)
|
||||
ret = qup_i2c_read_one_v2(qup, &msgs[idx]);
|
||||
else
|
||||
ret = qup_i2c_write_one_v2(qup, &msgs[idx]);
|
||||
}
|
||||
- } while ((idx++ < (num - 1)) && !use_dma && !ret);
|
||||
+ } while ((idx++ < (num - 1)) && !ret);
|
||||
|
||||
if (!ret)
|
||||
ret = qup_i2c_change_state(qup, QUP_RESET_STATE);
|
||||
@ -1,174 +0,0 @@
|
||||
From 6d5f37f166bb07b04b4d42e9d1f5427b7931cd3c Mon Sep 17 00:00:00 2001
|
||||
From: Abhishek Sahu <absahu@codeaurora.org>
|
||||
Date: Mon, 12 Mar 2018 18:44:53 +0530
|
||||
Subject: [PATCH 04/13] i2c: qup: remove redundant variables for BAM SG count
|
||||
|
||||
The rx_nents and tx_nents are redundant. rx_buf and tx_buf can
|
||||
be used for total number of SG entries. Since rx_buf and tx_buf
|
||||
give the impression that it is buffer instead of count so rename
|
||||
it to tx_cnt and rx_cnt for giving it more meaningful variable
|
||||
name.
|
||||
|
||||
Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
|
||||
Reviewed-by: Austin Christ <austinwc@codeaurora.org>
|
||||
Reviewed-by: Andy Gross <andy.gross@linaro.org>
|
||||
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
|
||||
---
|
||||
drivers/i2c/busses/i2c-qup.c | 42 ++++++++++++++++--------------------
|
||||
1 file changed, 18 insertions(+), 24 deletions(-)
|
||||
|
||||
--- a/drivers/i2c/busses/i2c-qup.c
|
||||
+++ b/drivers/i2c/busses/i2c-qup.c
|
||||
@@ -683,8 +683,8 @@ static int qup_i2c_bam_do_xfer(struct qu
|
||||
struct dma_async_tx_descriptor *txd, *rxd = NULL;
|
||||
int ret = 0, idx = 0, limit = QUP_READ_LIMIT;
|
||||
dma_cookie_t cookie_rx, cookie_tx;
|
||||
- u32 rx_nents = 0, tx_nents = 0, len, blocks, rem;
|
||||
- u32 i, tlen, tx_len, tx_buf = 0, rx_buf = 0, off = 0;
|
||||
+ u32 len, blocks, rem;
|
||||
+ u32 i, tlen, tx_len, tx_cnt = 0, rx_cnt = 0, off = 0;
|
||||
u8 *tags;
|
||||
|
||||
while (idx < num) {
|
||||
@@ -698,9 +698,6 @@ static int qup_i2c_bam_do_xfer(struct qu
|
||||
rem = msg->len - (blocks - 1) * limit;
|
||||
|
||||
if (msg->flags & I2C_M_RD) {
|
||||
- rx_nents += (blocks * 2) + 1;
|
||||
- tx_nents += 1;
|
||||
-
|
||||
while (qup->blk.pos < blocks) {
|
||||
tlen = (i == (blocks - 1)) ? rem : limit;
|
||||
tags = &qup->start_tag.start[off + len];
|
||||
@@ -708,14 +705,14 @@ static int qup_i2c_bam_do_xfer(struct qu
|
||||
qup->blk.data_len -= tlen;
|
||||
|
||||
/* scratch buf to read the start and len tags */
|
||||
- ret = qup_sg_set_buf(&qup->brx.sg[rx_buf++],
|
||||
+ ret = qup_sg_set_buf(&qup->brx.sg[rx_cnt++],
|
||||
&qup->brx.tag.start[0],
|
||||
2, qup, DMA_FROM_DEVICE);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
- ret = qup_sg_set_buf(&qup->brx.sg[rx_buf++],
|
||||
+ ret = qup_sg_set_buf(&qup->brx.sg[rx_cnt++],
|
||||
&msg->buf[limit * i],
|
||||
tlen, qup,
|
||||
DMA_FROM_DEVICE);
|
||||
@@ -725,7 +722,7 @@ static int qup_i2c_bam_do_xfer(struct qu
|
||||
i++;
|
||||
qup->blk.pos = i;
|
||||
}
|
||||
- ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++],
|
||||
+ ret = qup_sg_set_buf(&qup->btx.sg[tx_cnt++],
|
||||
&qup->start_tag.start[off],
|
||||
len, qup, DMA_TO_DEVICE);
|
||||
if (ret)
|
||||
@@ -733,28 +730,26 @@ static int qup_i2c_bam_do_xfer(struct qu
|
||||
|
||||
off += len;
|
||||
/* scratch buf to read the BAM EOT and FLUSH tags */
|
||||
- ret = qup_sg_set_buf(&qup->brx.sg[rx_buf++],
|
||||
+ ret = qup_sg_set_buf(&qup->brx.sg[rx_cnt++],
|
||||
&qup->brx.tag.start[0],
|
||||
2, qup, DMA_FROM_DEVICE);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
- tx_nents += (blocks * 2);
|
||||
-
|
||||
while (qup->blk.pos < blocks) {
|
||||
tlen = (i == (blocks - 1)) ? rem : limit;
|
||||
tags = &qup->start_tag.start[off + tx_len];
|
||||
len = qup_i2c_set_tags(tags, qup, msg, 1);
|
||||
qup->blk.data_len -= tlen;
|
||||
|
||||
- ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++],
|
||||
+ ret = qup_sg_set_buf(&qup->btx.sg[tx_cnt++],
|
||||
tags, len,
|
||||
qup, DMA_TO_DEVICE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
tx_len += len;
|
||||
- ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++],
|
||||
+ ret = qup_sg_set_buf(&qup->btx.sg[tx_cnt++],
|
||||
&msg->buf[limit * i],
|
||||
tlen, qup, DMA_TO_DEVICE);
|
||||
if (ret)
|
||||
@@ -766,26 +761,25 @@ static int qup_i2c_bam_do_xfer(struct qu
|
||||
|
||||
if (idx == (num - 1)) {
|
||||
len = 1;
|
||||
- if (rx_nents) {
|
||||
+ if (rx_cnt) {
|
||||
qup->btx.tag.start[0] =
|
||||
QUP_BAM_INPUT_EOT;
|
||||
len++;
|
||||
}
|
||||
qup->btx.tag.start[len - 1] =
|
||||
QUP_BAM_FLUSH_STOP;
|
||||
- ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++],
|
||||
+ ret = qup_sg_set_buf(&qup->btx.sg[tx_cnt++],
|
||||
&qup->btx.tag.start[0],
|
||||
len, qup, DMA_TO_DEVICE);
|
||||
if (ret)
|
||||
return ret;
|
||||
- tx_nents += 1;
|
||||
}
|
||||
}
|
||||
idx++;
|
||||
msg++;
|
||||
}
|
||||
|
||||
- txd = dmaengine_prep_slave_sg(qup->btx.dma, qup->btx.sg, tx_nents,
|
||||
+ txd = dmaengine_prep_slave_sg(qup->btx.dma, qup->btx.sg, tx_cnt,
|
||||
DMA_MEM_TO_DEV,
|
||||
DMA_PREP_INTERRUPT | DMA_PREP_FENCE);
|
||||
if (!txd) {
|
||||
@@ -794,7 +788,7 @@ static int qup_i2c_bam_do_xfer(struct qu
|
||||
goto desc_err;
|
||||
}
|
||||
|
||||
- if (!rx_nents) {
|
||||
+ if (!rx_cnt) {
|
||||
txd->callback = qup_i2c_bam_cb;
|
||||
txd->callback_param = qup;
|
||||
}
|
||||
@@ -807,9 +801,9 @@ static int qup_i2c_bam_do_xfer(struct qu
|
||||
|
||||
dma_async_issue_pending(qup->btx.dma);
|
||||
|
||||
- if (rx_nents) {
|
||||
+ if (rx_cnt) {
|
||||
rxd = dmaengine_prep_slave_sg(qup->brx.dma, qup->brx.sg,
|
||||
- rx_nents, DMA_DEV_TO_MEM,
|
||||
+ rx_cnt, DMA_DEV_TO_MEM,
|
||||
DMA_PREP_INTERRUPT);
|
||||
if (!rxd) {
|
||||
dev_err(qup->dev, "failed to get rx desc\n");
|
||||
@@ -844,7 +838,7 @@ static int qup_i2c_bam_do_xfer(struct qu
|
||||
goto desc_err;
|
||||
}
|
||||
|
||||
- if (rx_nents)
|
||||
+ if (rx_cnt)
|
||||
writel(QUP_BAM_INPUT_EOT,
|
||||
qup->base + QUP_OUT_FIFO_BASE);
|
||||
|
||||
@@ -862,10 +856,10 @@ static int qup_i2c_bam_do_xfer(struct qu
|
||||
}
|
||||
|
||||
desc_err:
|
||||
- dma_unmap_sg(qup->dev, qup->btx.sg, tx_nents, DMA_TO_DEVICE);
|
||||
+ dma_unmap_sg(qup->dev, qup->btx.sg, tx_cnt, DMA_TO_DEVICE);
|
||||
|
||||
- if (rx_nents)
|
||||
- dma_unmap_sg(qup->dev, qup->brx.sg, rx_nents,
|
||||
+ if (rx_cnt)
|
||||
+ dma_unmap_sg(qup->dev, qup->brx.sg, rx_cnt,
|
||||
DMA_FROM_DEVICE);
|
||||
|
||||
return ret;
|
||||
@ -1,126 +0,0 @@
|
||||
From c5adc0fa63a930e3313c74bb7c1d4d158130eb41 Mon Sep 17 00:00:00 2001
|
||||
From: Abhishek Sahu <absahu@codeaurora.org>
|
||||
Date: Mon, 12 Mar 2018 18:44:54 +0530
|
||||
Subject: [PATCH 05/13] i2c: qup: schedule EOT and FLUSH tags at the end of
|
||||
transfer
|
||||
|
||||
The role of FLUSH and EOT tag is to flush already scheduled
|
||||
descriptors in BAM HW in case of error. EOT is required only
|
||||
when descriptors are scheduled in RX FIFO. If all the messages
|
||||
are WRITE, then only FLUSH tag will be used.
|
||||
|
||||
A single BAM transfer can have multiple read and write messages.
|
||||
The EOT and FLUSH tags should be scheduled at the end of BAM HW
|
||||
descriptors. Since the READ and WRITE can be present in any order
|
||||
so for some of the cases, these tags are not being written
|
||||
correctly.
|
||||
|
||||
Following is one of the example
|
||||
|
||||
READ, READ, READ, READ
|
||||
|
||||
Currently EOT and FLUSH tags are being written after each READ.
|
||||
If QUP gets NACK for first READ itself, then flush will be
|
||||
triggered. It will look for first FLUSH tag in TX FIFO and will
|
||||
stop there so only descriptors for first READ descriptors be
|
||||
flushed. All the scheduled descriptors should be cleared to
|
||||
generate BAM DMA completion.
|
||||
|
||||
Now this patch is scheduling FLUSH and EOT only once after all the
|
||||
descriptors. So, flush will clear all the scheduled descriptors and
|
||||
BAM will generate the completion interrupt.
|
||||
|
||||
Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
|
||||
Reviewed-by: Sricharan R <sricharan@codeaurora.org>
|
||||
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
|
||||
---
|
||||
drivers/i2c/busses/i2c-qup.c | 39 ++++++++++++++++++++++--------------
|
||||
1 file changed, 24 insertions(+), 15 deletions(-)
|
||||
|
||||
--- a/drivers/i2c/busses/i2c-qup.c
|
||||
+++ b/drivers/i2c/busses/i2c-qup.c
|
||||
@@ -551,7 +551,7 @@ static int qup_i2c_set_tags_smb(u16 addr
|
||||
}
|
||||
|
||||
static int qup_i2c_set_tags(u8 *tags, struct qup_i2c_dev *qup,
|
||||
- struct i2c_msg *msg, int is_dma)
|
||||
+ struct i2c_msg *msg)
|
||||
{
|
||||
u16 addr = i2c_8bit_addr_from_msg(msg);
|
||||
int len = 0;
|
||||
@@ -592,11 +592,6 @@ static int qup_i2c_set_tags(u8 *tags, st
|
||||
else
|
||||
tags[len++] = data_len;
|
||||
|
||||
- if ((msg->flags & I2C_M_RD) && last && is_dma) {
|
||||
- tags[len++] = QUP_BAM_INPUT_EOT;
|
||||
- tags[len++] = QUP_BAM_FLUSH_STOP;
|
||||
- }
|
||||
-
|
||||
return len;
|
||||
}
|
||||
|
||||
@@ -605,7 +600,7 @@ static int qup_i2c_issue_xfer_v2(struct
|
||||
int data_len = 0, tag_len, index;
|
||||
int ret;
|
||||
|
||||
- tag_len = qup_i2c_set_tags(qup->blk.tags, qup, msg, 0);
|
||||
+ tag_len = qup_i2c_set_tags(qup->blk.tags, qup, msg);
|
||||
index = msg->len - qup->blk.data_len;
|
||||
|
||||
/* only tags are written for read */
|
||||
@@ -701,7 +696,7 @@ static int qup_i2c_bam_do_xfer(struct qu
|
||||
while (qup->blk.pos < blocks) {
|
||||
tlen = (i == (blocks - 1)) ? rem : limit;
|
||||
tags = &qup->start_tag.start[off + len];
|
||||
- len += qup_i2c_set_tags(tags, qup, msg, 1);
|
||||
+ len += qup_i2c_set_tags(tags, qup, msg);
|
||||
qup->blk.data_len -= tlen;
|
||||
|
||||
/* scratch buf to read the start and len tags */
|
||||
@@ -729,17 +724,11 @@ static int qup_i2c_bam_do_xfer(struct qu
|
||||
return ret;
|
||||
|
||||
off += len;
|
||||
- /* scratch buf to read the BAM EOT and FLUSH tags */
|
||||
- ret = qup_sg_set_buf(&qup->brx.sg[rx_cnt++],
|
||||
- &qup->brx.tag.start[0],
|
||||
- 2, qup, DMA_FROM_DEVICE);
|
||||
- if (ret)
|
||||
- return ret;
|
||||
} else {
|
||||
while (qup->blk.pos < blocks) {
|
||||
tlen = (i == (blocks - 1)) ? rem : limit;
|
||||
tags = &qup->start_tag.start[off + tx_len];
|
||||
- len = qup_i2c_set_tags(tags, qup, msg, 1);
|
||||
+ len = qup_i2c_set_tags(tags, qup, msg);
|
||||
qup->blk.data_len -= tlen;
|
||||
|
||||
ret = qup_sg_set_buf(&qup->btx.sg[tx_cnt++],
|
||||
@@ -779,6 +768,26 @@ static int qup_i2c_bam_do_xfer(struct qu
|
||||
msg++;
|
||||
}
|
||||
|
||||
+ /* schedule the EOT and FLUSH I2C tags */
|
||||
+ len = 1;
|
||||
+ if (rx_cnt) {
|
||||
+ qup->btx.tag.start[0] = QUP_BAM_INPUT_EOT;
|
||||
+ len++;
|
||||
+
|
||||
+ /* scratch buf to read the BAM EOT and FLUSH tags */
|
||||
+ ret = qup_sg_set_buf(&qup->brx.sg[rx_cnt++],
|
||||
+ &qup->brx.tag.start[0],
|
||||
+ 2, qup, DMA_FROM_DEVICE);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ qup->btx.tag.start[len - 1] = QUP_BAM_FLUSH_STOP;
|
||||
+ ret = qup_sg_set_buf(&qup->btx.sg[tx_cnt++], &qup->btx.tag.start[0],
|
||||
+ len, qup, DMA_TO_DEVICE);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
txd = dmaengine_prep_slave_sg(qup->btx.dma, qup->btx.sg, tx_cnt,
|
||||
DMA_MEM_TO_DEV,
|
||||
DMA_PREP_INTERRUPT | DMA_PREP_FENCE);
|
||||
@ -1,33 +0,0 @@
|
||||
From 7e6c35fe602df6821b3e7db5b1ba656162750fda Mon Sep 17 00:00:00 2001
|
||||
From: Abhishek Sahu <absahu@codeaurora.org>
|
||||
Date: Mon, 12 Mar 2018 18:44:55 +0530
|
||||
Subject: [PATCH 06/13] i2c: qup: fix the transfer length for BAM RX EOT FLUSH
|
||||
tags
|
||||
|
||||
In case of FLUSH operation, BAM copies INPUT EOT FLUSH (0x94)
|
||||
instead of normal EOT (0x93) tag in input data stream when an
|
||||
input EOT tag is received during flush operation. So only one tag
|
||||
will be written instead of 2 separate tags.
|
||||
|
||||
Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
|
||||
Reviewed-by: Andy Gross <andy.gross@linaro.org>
|
||||
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
|
||||
---
|
||||
drivers/i2c/busses/i2c-qup.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/i2c/busses/i2c-qup.c
|
||||
+++ b/drivers/i2c/busses/i2c-qup.c
|
||||
@@ -774,10 +774,10 @@ static int qup_i2c_bam_do_xfer(struct qu
|
||||
qup->btx.tag.start[0] = QUP_BAM_INPUT_EOT;
|
||||
len++;
|
||||
|
||||
- /* scratch buf to read the BAM EOT and FLUSH tags */
|
||||
+ /* scratch buf to read the BAM EOT FLUSH tags */
|
||||
ret = qup_sg_set_buf(&qup->brx.sg[rx_cnt++],
|
||||
&qup->brx.tag.start[0],
|
||||
- 2, qup, DMA_FROM_DEVICE);
|
||||
+ 1, qup, DMA_FROM_DEVICE);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
@ -1,90 +0,0 @@
|
||||
From 3f450d3eea14799b14192231840c1753a660f150 Mon Sep 17 00:00:00 2001
|
||||
From: Abhishek Sahu <absahu@codeaurora.org>
|
||||
Date: Mon, 12 Mar 2018 18:44:56 +0530
|
||||
Subject: [PATCH 07/13] i2c: qup: proper error handling for i2c error in BAM
|
||||
mode
|
||||
|
||||
Currently the i2c error handling in BAM mode is not working
|
||||
properly in stress condition.
|
||||
|
||||
1. After an error, the FIFO are being written with FLUSH and
|
||||
EOT tags which should not be required since already these tags
|
||||
have been written in BAM descriptor itself.
|
||||
|
||||
2. QUP state is being moved to RESET in IRQ handler in case
|
||||
of error. When QUP HW encounters an error in BAM mode then it
|
||||
moves the QUP STATE to PAUSE state. In this case, I2C_FLUSH
|
||||
command needs to be executed while moving to RUN_STATE by writing
|
||||
to the QUP_STATE register with the I2C_FLUSH bit set to 1.
|
||||
|
||||
3. In Error case, sometimes, QUP generates more than one
|
||||
interrupt which will trigger the complete again. After an error,
|
||||
the flush operation will be scheduled after doing
|
||||
reinit_completion which should be triggered by BAM IRQ callback.
|
||||
If the second QUP IRQ comes during this time then it will call
|
||||
the complete and the transfer function will assume the all the
|
||||
BAM HW descriptors have been completed.
|
||||
|
||||
4. The release DMA is being called after each error which
|
||||
will free the DMA tx and rx channels. The error like NACK is very
|
||||
common in I2C transfer and every time this will be overhead. Now,
|
||||
since the error handling is proper so this release channel can be
|
||||
completely avoided.
|
||||
|
||||
Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
|
||||
Reviewed-by: Sricharan R <sricharan@codeaurora.org>
|
||||
Reviewed-by: Austin Christ <austinwc@codeaurora.org>
|
||||
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
|
||||
---
|
||||
drivers/i2c/busses/i2c-qup.c | 25 ++++++++++++++++---------
|
||||
1 file changed, 16 insertions(+), 9 deletions(-)
|
||||
|
||||
--- a/drivers/i2c/busses/i2c-qup.c
|
||||
+++ b/drivers/i2c/busses/i2c-qup.c
|
||||
@@ -219,9 +219,24 @@ static irqreturn_t qup_i2c_interrupt(int
|
||||
if (bus_err)
|
||||
writel(bus_err, qup->base + QUP_I2C_STATUS);
|
||||
|
||||
+ /*
|
||||
+ * Check for BAM mode and returns if already error has come for current
|
||||
+ * transfer. In Error case, sometimes, QUP generates more than one
|
||||
+ * interrupt.
|
||||
+ */
|
||||
+ if (qup->use_dma && (qup->qup_err || qup->bus_err))
|
||||
+ return IRQ_HANDLED;
|
||||
+
|
||||
/* Reset the QUP State in case of error */
|
||||
if (qup_err || bus_err) {
|
||||
- writel(QUP_RESET_STATE, qup->base + QUP_STATE);
|
||||
+ /*
|
||||
+ * Don’t reset the QUP state in case of BAM mode. The BAM
|
||||
+ * flush operation needs to be scheduled in transfer function
|
||||
+ * which will clear the remaining schedule descriptors in BAM
|
||||
+ * HW FIFO and generates the BAM interrupt.
|
||||
+ */
|
||||
+ if (!qup->use_dma)
|
||||
+ writel(QUP_RESET_STATE, qup->base + QUP_STATE);
|
||||
goto done;
|
||||
}
|
||||
|
||||
@@ -847,20 +862,12 @@ static int qup_i2c_bam_do_xfer(struct qu
|
||||
goto desc_err;
|
||||
}
|
||||
|
||||
- if (rx_cnt)
|
||||
- writel(QUP_BAM_INPUT_EOT,
|
||||
- qup->base + QUP_OUT_FIFO_BASE);
|
||||
-
|
||||
- writel(QUP_BAM_FLUSH_STOP, qup->base + QUP_OUT_FIFO_BASE);
|
||||
-
|
||||
qup_i2c_flush(qup);
|
||||
|
||||
/* wait for remaining interrupts to occur */
|
||||
if (!wait_for_completion_timeout(&qup->xfer, HZ))
|
||||
dev_err(qup->dev, "flush timed out\n");
|
||||
|
||||
- qup_i2c_rel_dma(qup);
|
||||
-
|
||||
ret = (qup->bus_err & QUP_I2C_NACK_FLAG) ? -ENXIO : -EIO;
|
||||
}
|
||||
|
||||
@ -1,54 +0,0 @@
|
||||
From 08f15963bc751bc818294c0f75a9aaca299c4052 Mon Sep 17 00:00:00 2001
|
||||
From: Abhishek Sahu <absahu@codeaurora.org>
|
||||
Date: Mon, 12 Mar 2018 18:44:57 +0530
|
||||
Subject: [PATCH 08/13] i2c: qup: use the complete transfer length to choose
|
||||
DMA mode
|
||||
|
||||
Currently each message length in complete transfer is being
|
||||
checked for determining DMA mode and if any of the message length
|
||||
is less than FIFO length then non DMA mode is being used which
|
||||
will increase overhead. DMA can be used for any length and it
|
||||
should be determined with complete transfer length. Now, this
|
||||
patch selects DMA mode if the total length is greater than FIFO
|
||||
length.
|
||||
|
||||
Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
|
||||
Reviewed-by: Austin Christ <austinwc@codeaurora.org>
|
||||
Reviewed-by: Andy Gross <andy.gross@linaro.org>
|
||||
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
|
||||
---
|
||||
drivers/i2c/busses/i2c-qup.c | 13 +++++++------
|
||||
1 file changed, 7 insertions(+), 6 deletions(-)
|
||||
|
||||
--- a/drivers/i2c/busses/i2c-qup.c
|
||||
+++ b/drivers/i2c/busses/i2c-qup.c
|
||||
@@ -1300,7 +1300,8 @@ static int qup_i2c_xfer_v2(struct i2c_ad
|
||||
int num)
|
||||
{
|
||||
struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
|
||||
- int ret, len, idx = 0;
|
||||
+ int ret, idx = 0;
|
||||
+ unsigned int total_len = 0;
|
||||
|
||||
qup->bus_err = 0;
|
||||
qup->qup_err = 0;
|
||||
@@ -1326,14 +1327,14 @@ static int qup_i2c_xfer_v2(struct i2c_ad
|
||||
goto out;
|
||||
}
|
||||
|
||||
- len = (msgs[idx].len > qup->out_fifo_sz) ||
|
||||
- (msgs[idx].len > qup->in_fifo_sz);
|
||||
-
|
||||
- if (is_vmalloc_addr(msgs[idx].buf) || !len)
|
||||
+ if (is_vmalloc_addr(msgs[idx].buf))
|
||||
break;
|
||||
+
|
||||
+ total_len += msgs[idx].len;
|
||||
}
|
||||
|
||||
- if (idx == num)
|
||||
+ if (idx == num && (total_len > qup->out_fifo_sz ||
|
||||
+ total_len > qup->in_fifo_sz))
|
||||
qup->use_dma = true;
|
||||
}
|
||||
|
||||
@ -1,61 +0,0 @@
|
||||
From ecb6e1e5f4352055a5761b945a833a925d51bf8d Mon Sep 17 00:00:00 2001
|
||||
From: Abhishek Sahu <absahu@codeaurora.org>
|
||||
Date: Mon, 12 Mar 2018 18:44:58 +0530
|
||||
Subject: [PATCH 09/13] i2c: qup: change completion timeout according to
|
||||
transfer length
|
||||
|
||||
Currently the completion timeout is being taken according to
|
||||
maximum transfer length which is too high if SCL is operating in
|
||||
high frequency. This patch calculates timeout on the basis of
|
||||
one-byte transfer time and uses the same for completion timeout.
|
||||
|
||||
Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
|
||||
Reviewed-by: Andy Gross <andy.gross@linaro.org>
|
||||
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
|
||||
---
|
||||
drivers/i2c/busses/i2c-qup.c | 13 ++++++++++---
|
||||
1 file changed, 10 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/drivers/i2c/busses/i2c-qup.c
|
||||
+++ b/drivers/i2c/busses/i2c-qup.c
|
||||
@@ -121,8 +121,12 @@
|
||||
#define MX_TX_RX_LEN SZ_64K
|
||||
#define MX_BLOCKS (MX_TX_RX_LEN / QUP_READ_LIMIT)
|
||||
|
||||
-/* Max timeout in ms for 32k bytes */
|
||||
-#define TOUT_MAX 300
|
||||
+/*
|
||||
+ * Minimum transfer timeout for i2c transfers in seconds. It will be added on
|
||||
+ * the top of maximum transfer time calculated from i2c bus speed to compensate
|
||||
+ * the overheads.
|
||||
+ */
|
||||
+#define TOUT_MIN 2
|
||||
|
||||
/* Default values. Use these if FW query fails */
|
||||
#define DEFAULT_CLK_FREQ 100000
|
||||
@@ -163,6 +167,7 @@ struct qup_i2c_dev {
|
||||
int in_blk_sz;
|
||||
|
||||
unsigned long one_byte_t;
|
||||
+ unsigned long xfer_timeout;
|
||||
struct qup_i2c_block blk;
|
||||
|
||||
struct i2c_msg *msg;
|
||||
@@ -849,7 +854,7 @@ static int qup_i2c_bam_do_xfer(struct qu
|
||||
dma_async_issue_pending(qup->brx.dma);
|
||||
}
|
||||
|
||||
- if (!wait_for_completion_timeout(&qup->xfer, TOUT_MAX * HZ)) {
|
||||
+ if (!wait_for_completion_timeout(&qup->xfer, qup->xfer_timeout)) {
|
||||
dev_err(qup->dev, "normal trans timed out\n");
|
||||
ret = -ETIMEDOUT;
|
||||
}
|
||||
@@ -1605,6 +1610,8 @@ nodma:
|
||||
*/
|
||||
one_bit_t = (USEC_PER_SEC / clk_freq) + 1;
|
||||
qup->one_byte_t = one_bit_t * 9;
|
||||
+ qup->xfer_timeout = TOUT_MIN * HZ +
|
||||
+ usecs_to_jiffies(MX_TX_RX_LEN * qup->one_byte_t);
|
||||
|
||||
dev_dbg(qup->dev, "IN:block:%d, fifo:%d, OUT:block:%d, fifo:%d\n",
|
||||
qup->in_blk_sz, qup->in_fifo_sz,
|
||||
@ -1,311 +0,0 @@
|
||||
From 6f2f0f6465acbd59391c43352ff0df77df1f01db Mon Sep 17 00:00:00 2001
|
||||
From: Abhishek Sahu <absahu@codeaurora.org>
|
||||
Date: Mon, 12 Mar 2018 18:44:59 +0530
|
||||
Subject: [PATCH 10/13] i2c: qup: fix buffer overflow for multiple msg of
|
||||
maximum xfer len
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
The BAM mode requires buffer for start tag data and tx, rx SG
|
||||
list. Currently, this is being taken for maximum transfer length
|
||||
(65K). But an I2C transfer can have multiple messages and each
|
||||
message can be of this maximum length so the buffer overflow will
|
||||
happen in this case. Since increasing buffer length won’t be
|
||||
feasible since an I2C transfer can contain any number of messages
|
||||
so this patch does following changes to make i2c transfers working
|
||||
for multiple messages case.
|
||||
|
||||
1. Calculate the required buffers for 2 maximum length messages
|
||||
(65K * 2).
|
||||
2. Split the descriptor formation and descriptor scheduling.
|
||||
The idea is to fit as many messages in one DMA transfers for 65K
|
||||
threshold value (max_xfer_sg_len). Whenever the sg_cnt is
|
||||
crossing this, then schedule the BAM transfer and subsequent
|
||||
transfer will again start from zero.
|
||||
|
||||
Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
|
||||
Reviewed-by: Andy Gross <andy.gross@linaro.org>
|
||||
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
|
||||
---
|
||||
drivers/i2c/busses/i2c-qup.c | 194 ++++++++++++++++++++---------------
|
||||
1 file changed, 110 insertions(+), 84 deletions(-)
|
||||
|
||||
--- a/drivers/i2c/busses/i2c-qup.c
|
||||
+++ b/drivers/i2c/busses/i2c-qup.c
|
||||
@@ -118,8 +118,12 @@
|
||||
#define ONE_BYTE 0x1
|
||||
#define QUP_I2C_MX_CONFIG_DURING_RUN BIT(31)
|
||||
|
||||
+/* Maximum transfer length for single DMA descriptor */
|
||||
#define MX_TX_RX_LEN SZ_64K
|
||||
#define MX_BLOCKS (MX_TX_RX_LEN / QUP_READ_LIMIT)
|
||||
+/* Maximum transfer length for all DMA descriptors */
|
||||
+#define MX_DMA_TX_RX_LEN (2 * MX_TX_RX_LEN)
|
||||
+#define MX_DMA_BLOCKS (MX_DMA_TX_RX_LEN / QUP_READ_LIMIT)
|
||||
|
||||
/*
|
||||
* Minimum transfer timeout for i2c transfers in seconds. It will be added on
|
||||
@@ -150,6 +154,7 @@ struct qup_i2c_bam {
|
||||
struct qup_i2c_tag tag;
|
||||
struct dma_chan *dma;
|
||||
struct scatterlist *sg;
|
||||
+ unsigned int sg_cnt;
|
||||
};
|
||||
|
||||
struct qup_i2c_dev {
|
||||
@@ -188,6 +193,8 @@ struct qup_i2c_dev {
|
||||
bool is_dma;
|
||||
/* To check if the current transfer is using DMA */
|
||||
bool use_dma;
|
||||
+ unsigned int max_xfer_sg_len;
|
||||
+ unsigned int tag_buf_pos;
|
||||
struct dma_pool *dpool;
|
||||
struct qup_i2c_tag start_tag;
|
||||
struct qup_i2c_bam brx;
|
||||
@@ -692,102 +699,87 @@ static int qup_i2c_req_dma(struct qup_i2
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg,
|
||||
- int num)
|
||||
+static int qup_i2c_bam_make_desc(struct qup_i2c_dev *qup, struct i2c_msg *msg)
|
||||
{
|
||||
- struct dma_async_tx_descriptor *txd, *rxd = NULL;
|
||||
- int ret = 0, idx = 0, limit = QUP_READ_LIMIT;
|
||||
- dma_cookie_t cookie_rx, cookie_tx;
|
||||
- u32 len, blocks, rem;
|
||||
- u32 i, tlen, tx_len, tx_cnt = 0, rx_cnt = 0, off = 0;
|
||||
+ int ret = 0, limit = QUP_READ_LIMIT;
|
||||
+ u32 len = 0, blocks, rem;
|
||||
+ u32 i = 0, tlen, tx_len = 0;
|
||||
u8 *tags;
|
||||
|
||||
- while (idx < num) {
|
||||
- tx_len = 0, len = 0, i = 0;
|
||||
-
|
||||
- qup->is_last = (idx == (num - 1));
|
||||
+ qup_i2c_set_blk_data(qup, msg);
|
||||
|
||||
- qup_i2c_set_blk_data(qup, msg);
|
||||
+ blocks = qup->blk.count;
|
||||
+ rem = msg->len - (blocks - 1) * limit;
|
||||
|
||||
- blocks = qup->blk.count;
|
||||
- rem = msg->len - (blocks - 1) * limit;
|
||||
+ if (msg->flags & I2C_M_RD) {
|
||||
+ while (qup->blk.pos < blocks) {
|
||||
+ tlen = (i == (blocks - 1)) ? rem : limit;
|
||||
+ tags = &qup->start_tag.start[qup->tag_buf_pos + len];
|
||||
+ len += qup_i2c_set_tags(tags, qup, msg);
|
||||
+ qup->blk.data_len -= tlen;
|
||||
+
|
||||
+ /* scratch buf to read the start and len tags */
|
||||
+ ret = qup_sg_set_buf(&qup->brx.sg[qup->brx.sg_cnt++],
|
||||
+ &qup->brx.tag.start[0],
|
||||
+ 2, qup, DMA_FROM_DEVICE);
|
||||
|
||||
- if (msg->flags & I2C_M_RD) {
|
||||
- while (qup->blk.pos < blocks) {
|
||||
- tlen = (i == (blocks - 1)) ? rem : limit;
|
||||
- tags = &qup->start_tag.start[off + len];
|
||||
- len += qup_i2c_set_tags(tags, qup, msg);
|
||||
- qup->blk.data_len -= tlen;
|
||||
-
|
||||
- /* scratch buf to read the start and len tags */
|
||||
- ret = qup_sg_set_buf(&qup->brx.sg[rx_cnt++],
|
||||
- &qup->brx.tag.start[0],
|
||||
- 2, qup, DMA_FROM_DEVICE);
|
||||
-
|
||||
- if (ret)
|
||||
- return ret;
|
||||
-
|
||||
- ret = qup_sg_set_buf(&qup->brx.sg[rx_cnt++],
|
||||
- &msg->buf[limit * i],
|
||||
- tlen, qup,
|
||||
- DMA_FROM_DEVICE);
|
||||
- if (ret)
|
||||
- return ret;
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
|
||||
- i++;
|
||||
- qup->blk.pos = i;
|
||||
- }
|
||||
- ret = qup_sg_set_buf(&qup->btx.sg[tx_cnt++],
|
||||
- &qup->start_tag.start[off],
|
||||
- len, qup, DMA_TO_DEVICE);
|
||||
+ ret = qup_sg_set_buf(&qup->brx.sg[qup->brx.sg_cnt++],
|
||||
+ &msg->buf[limit * i],
|
||||
+ tlen, qup,
|
||||
+ DMA_FROM_DEVICE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
- off += len;
|
||||
- } else {
|
||||
- while (qup->blk.pos < blocks) {
|
||||
- tlen = (i == (blocks - 1)) ? rem : limit;
|
||||
- tags = &qup->start_tag.start[off + tx_len];
|
||||
- len = qup_i2c_set_tags(tags, qup, msg);
|
||||
- qup->blk.data_len -= tlen;
|
||||
-
|
||||
- ret = qup_sg_set_buf(&qup->btx.sg[tx_cnt++],
|
||||
- tags, len,
|
||||
- qup, DMA_TO_DEVICE);
|
||||
- if (ret)
|
||||
- return ret;
|
||||
-
|
||||
- tx_len += len;
|
||||
- ret = qup_sg_set_buf(&qup->btx.sg[tx_cnt++],
|
||||
- &msg->buf[limit * i],
|
||||
- tlen, qup, DMA_TO_DEVICE);
|
||||
- if (ret)
|
||||
- return ret;
|
||||
- i++;
|
||||
- qup->blk.pos = i;
|
||||
- }
|
||||
- off += tx_len;
|
||||
+ i++;
|
||||
+ qup->blk.pos = i;
|
||||
+ }
|
||||
+ ret = qup_sg_set_buf(&qup->btx.sg[qup->btx.sg_cnt++],
|
||||
+ &qup->start_tag.start[qup->tag_buf_pos],
|
||||
+ len, qup, DMA_TO_DEVICE);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
|
||||
- if (idx == (num - 1)) {
|
||||
- len = 1;
|
||||
- if (rx_cnt) {
|
||||
- qup->btx.tag.start[0] =
|
||||
- QUP_BAM_INPUT_EOT;
|
||||
- len++;
|
||||
- }
|
||||
- qup->btx.tag.start[len - 1] =
|
||||
- QUP_BAM_FLUSH_STOP;
|
||||
- ret = qup_sg_set_buf(&qup->btx.sg[tx_cnt++],
|
||||
- &qup->btx.tag.start[0],
|
||||
- len, qup, DMA_TO_DEVICE);
|
||||
- if (ret)
|
||||
- return ret;
|
||||
- }
|
||||
+ qup->tag_buf_pos += len;
|
||||
+ } else {
|
||||
+ while (qup->blk.pos < blocks) {
|
||||
+ tlen = (i == (blocks - 1)) ? rem : limit;
|
||||
+ tags = &qup->start_tag.start[qup->tag_buf_pos + tx_len];
|
||||
+ len = qup_i2c_set_tags(tags, qup, msg);
|
||||
+ qup->blk.data_len -= tlen;
|
||||
+
|
||||
+ ret = qup_sg_set_buf(&qup->btx.sg[qup->btx.sg_cnt++],
|
||||
+ tags, len,
|
||||
+ qup, DMA_TO_DEVICE);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ tx_len += len;
|
||||
+ ret = qup_sg_set_buf(&qup->btx.sg[qup->btx.sg_cnt++],
|
||||
+ &msg->buf[limit * i],
|
||||
+ tlen, qup, DMA_TO_DEVICE);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ i++;
|
||||
+ qup->blk.pos = i;
|
||||
}
|
||||
- idx++;
|
||||
- msg++;
|
||||
+
|
||||
+ qup->tag_buf_pos += tx_len;
|
||||
}
|
||||
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int qup_i2c_bam_schedule_desc(struct qup_i2c_dev *qup)
|
||||
+{
|
||||
+ struct dma_async_tx_descriptor *txd, *rxd = NULL;
|
||||
+ int ret = 0;
|
||||
+ dma_cookie_t cookie_rx, cookie_tx;
|
||||
+ u32 len = 0;
|
||||
+ u32 tx_cnt = qup->btx.sg_cnt, rx_cnt = qup->brx.sg_cnt;
|
||||
+
|
||||
/* schedule the EOT and FLUSH I2C tags */
|
||||
len = 1;
|
||||
if (rx_cnt) {
|
||||
@@ -886,11 +878,19 @@ desc_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
+static void qup_i2c_bam_clear_tag_buffers(struct qup_i2c_dev *qup)
|
||||
+{
|
||||
+ qup->btx.sg_cnt = 0;
|
||||
+ qup->brx.sg_cnt = 0;
|
||||
+ qup->tag_buf_pos = 0;
|
||||
+}
|
||||
+
|
||||
static int qup_i2c_bam_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
|
||||
int num)
|
||||
{
|
||||
struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
|
||||
int ret = 0;
|
||||
+ int idx = 0;
|
||||
|
||||
enable_irq(qup->irq);
|
||||
ret = qup_i2c_req_dma(qup);
|
||||
@@ -913,9 +913,34 @@ static int qup_i2c_bam_xfer(struct i2c_a
|
||||
goto out;
|
||||
|
||||
writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
|
||||
+ qup_i2c_bam_clear_tag_buffers(qup);
|
||||
+
|
||||
+ for (idx = 0; idx < num; idx++) {
|
||||
+ qup->msg = msg + idx;
|
||||
+ qup->is_last = idx == (num - 1);
|
||||
+
|
||||
+ ret = qup_i2c_bam_make_desc(qup, qup->msg);
|
||||
+ if (ret)
|
||||
+ break;
|
||||
+
|
||||
+ /*
|
||||
+ * Make DMA descriptor and schedule the BAM transfer if its
|
||||
+ * already crossed the maximum length. Since the memory for all
|
||||
+ * tags buffers have been taken for 2 maximum possible
|
||||
+ * transfers length so it will never cross the buffer actual
|
||||
+ * length.
|
||||
+ */
|
||||
+ if (qup->btx.sg_cnt > qup->max_xfer_sg_len ||
|
||||
+ qup->brx.sg_cnt > qup->max_xfer_sg_len ||
|
||||
+ qup->is_last) {
|
||||
+ ret = qup_i2c_bam_schedule_desc(qup);
|
||||
+ if (ret)
|
||||
+ break;
|
||||
+
|
||||
+ qup_i2c_bam_clear_tag_buffers(qup);
|
||||
+ }
|
||||
+ }
|
||||
|
||||
- qup->msg = msg;
|
||||
- ret = qup_i2c_bam_do_xfer(qup, qup->msg, num);
|
||||
out:
|
||||
disable_irq(qup->irq);
|
||||
|
||||
@@ -1468,7 +1493,8 @@ static int qup_i2c_probe(struct platform
|
||||
else if (ret != 0)
|
||||
goto nodma;
|
||||
|
||||
- blocks = (MX_BLOCKS << 1) + 1;
|
||||
+ qup->max_xfer_sg_len = (MX_BLOCKS << 1);
|
||||
+ blocks = (MX_DMA_BLOCKS << 1) + 1;
|
||||
qup->btx.sg = devm_kzalloc(&pdev->dev,
|
||||
sizeof(*qup->btx.sg) * blocks,
|
||||
GFP_KERNEL);
|
||||
@@ -1611,7 +1637,7 @@ nodma:
|
||||
one_bit_t = (USEC_PER_SEC / clk_freq) + 1;
|
||||
qup->one_byte_t = one_bit_t * 9;
|
||||
qup->xfer_timeout = TOUT_MIN * HZ +
|
||||
- usecs_to_jiffies(MX_TX_RX_LEN * qup->one_byte_t);
|
||||
+ usecs_to_jiffies(MX_DMA_TX_RX_LEN * qup->one_byte_t);
|
||||
|
||||
dev_dbg(qup->dev, "IN:block:%d, fifo:%d, OUT:block:%d, fifo:%d\n",
|
||||
qup->in_blk_sz, qup->in_fifo_sz,
|
||||
@ -1,43 +0,0 @@
|
||||
From f7714b4e451bdcb7918b9aad14af22684ceac638 Mon Sep 17 00:00:00 2001
|
||||
From: Abhishek Sahu <absahu@codeaurora.org>
|
||||
Date: Mon, 12 Mar 2018 18:45:00 +0530
|
||||
Subject: [PATCH 11/13] i2c: qup: send NACK for last read sub transfers
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
According to I2c specification, “If a master-receiver sends a
|
||||
repeated START condition, it sends a not-acknowledge (A) just
|
||||
before the repeated START condition”. QUP v2 supports sending
|
||||
of NACK without stop with QUP_TAG_V2_DATARD_NACK so added the
|
||||
same.
|
||||
|
||||
Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
|
||||
Reviewed-by: Austin Christ <austinwc@codeaurora.org>
|
||||
Reviewed-by: Andy Gross <andy.gross@linaro.org>
|
||||
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
|
||||
---
|
||||
drivers/i2c/busses/i2c-qup.c | 5 ++++-
|
||||
1 file changed, 4 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/i2c/busses/i2c-qup.c
|
||||
+++ b/drivers/i2c/busses/i2c-qup.c
|
||||
@@ -104,6 +104,7 @@
|
||||
#define QUP_TAG_V2_DATAWR 0x82
|
||||
#define QUP_TAG_V2_DATAWR_STOP 0x83
|
||||
#define QUP_TAG_V2_DATARD 0x85
|
||||
+#define QUP_TAG_V2_DATARD_NACK 0x86
|
||||
#define QUP_TAG_V2_DATARD_STOP 0x87
|
||||
|
||||
/* Status, Error flags */
|
||||
@@ -606,7 +607,9 @@ static int qup_i2c_set_tags(u8 *tags, st
|
||||
tags[len++] = QUP_TAG_V2_DATAWR_STOP;
|
||||
} else {
|
||||
if (msg->flags & I2C_M_RD)
|
||||
- tags[len++] = QUP_TAG_V2_DATARD;
|
||||
+ tags[len++] = qup->blk.pos == (qup->blk.count - 1) ?
|
||||
+ QUP_TAG_V2_DATARD_NACK :
|
||||
+ QUP_TAG_V2_DATARD;
|
||||
else
|
||||
tags[len++] = QUP_TAG_V2_DATAWR;
|
||||
}
|
||||
@ -1,579 +0,0 @@
|
||||
From fbfab1ab065879370541caf0e514987368eb41b2 Mon Sep 17 00:00:00 2001
|
||||
From: Abhishek Sahu <absahu@codeaurora.org>
|
||||
Date: Mon, 12 Mar 2018 18:45:01 +0530
|
||||
Subject: [PATCH 12/13] i2c: qup: reorganization of driver code to remove
|
||||
polling for qup v1
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Following are the major issues in current driver code
|
||||
|
||||
1. The current driver simply assumes the transfer completion
|
||||
whenever its gets any non-error interrupts and then simply do the
|
||||
polling of available/free bytes in FIFO.
|
||||
2. The block mode is not working properly since no handling in
|
||||
being done for OUT_BLOCK_WRITE_REQ and IN_BLOCK_READ_REQ.
|
||||
|
||||
Because of above, i2c v1 transfers of size greater than 32 are failing
|
||||
with following error message
|
||||
|
||||
i2c_qup 78b6000.i2c: timeout for fifo out full
|
||||
|
||||
To make block mode working properly and move to use the interrupts
|
||||
instead of polling, major code reorganization is required. Following
|
||||
are the major changes done in this patch
|
||||
|
||||
1. Remove the polling of TX FIFO free space and RX FIFO available
|
||||
bytes and move to interrupts completely. QUP has QUP_MX_OUTPUT_DONE,
|
||||
QUP_MX_INPUT_DONE, OUT_BLOCK_WRITE_REQ and IN_BLOCK_READ_REQ
|
||||
interrupts to handle FIFO’s properly so check all these interrupts.
|
||||
2. During write, For FIFO mode, TX FIFO can be directly written
|
||||
without checking for FIFO space. For block mode, the QUP will generate
|
||||
OUT_BLOCK_WRITE_REQ interrupt whenever it has block size of available
|
||||
space.
|
||||
3. During read, both TX and RX FIFO will be used. TX will be used
|
||||
for writing tags and RX will be used for receiving the data. In QUP,
|
||||
TX and RX can operate in separate mode so configure modes accordingly.
|
||||
4. For read FIFO mode, wait for QUP_MX_INPUT_DONE interrupt which
|
||||
will be generated after all the bytes have been copied in RX FIFO. For
|
||||
read Block mode, QUP will generate IN_BLOCK_READ_REQ interrupts
|
||||
whenever it has block size of available data.
|
||||
|
||||
Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
|
||||
Reviewed-by: Sricharan R <sricharan@codeaurora.org>
|
||||
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
|
||||
---
|
||||
drivers/i2c/busses/i2c-qup.c | 366 +++++++++++++++++++++--------------
|
||||
1 file changed, 223 insertions(+), 143 deletions(-)
|
||||
|
||||
--- a/drivers/i2c/busses/i2c-qup.c
|
||||
+++ b/drivers/i2c/busses/i2c-qup.c
|
||||
@@ -64,8 +64,11 @@
|
||||
#define QUP_IN_SVC_FLAG BIT(9)
|
||||
#define QUP_MX_OUTPUT_DONE BIT(10)
|
||||
#define QUP_MX_INPUT_DONE BIT(11)
|
||||
+#define OUT_BLOCK_WRITE_REQ BIT(12)
|
||||
+#define IN_BLOCK_READ_REQ BIT(13)
|
||||
|
||||
/* I2C mini core related values */
|
||||
+#define QUP_NO_INPUT BIT(7)
|
||||
#define QUP_CLOCK_AUTO_GATE BIT(13)
|
||||
#define I2C_MINI_CORE (2 << 8)
|
||||
#define I2C_N_VAL 15
|
||||
@@ -137,13 +140,36 @@
|
||||
#define DEFAULT_CLK_FREQ 100000
|
||||
#define DEFAULT_SRC_CLK 20000000
|
||||
|
||||
+/*
|
||||
+ * count: no of blocks
|
||||
+ * pos: current block number
|
||||
+ * tx_tag_len: tx tag length for current block
|
||||
+ * rx_tag_len: rx tag length for current block
|
||||
+ * data_len: remaining data length for current message
|
||||
+ * total_tx_len: total tx length including tag bytes for current QUP transfer
|
||||
+ * total_rx_len: total rx length including tag bytes for current QUP transfer
|
||||
+ * tx_fifo_free: number of free bytes in current QUP block write.
|
||||
+ * fifo_available: number of available bytes in RX FIFO for current
|
||||
+ * QUP block read
|
||||
+ * rx_bytes_read: if all the bytes have been read from rx FIFO.
|
||||
+ * is_tx_blk_mode: whether tx uses block or FIFO mode in case of non BAM xfer.
|
||||
+ * is_rx_blk_mode: whether rx uses block or FIFO mode in case of non BAM xfer.
|
||||
+ * tags: contains tx tag bytes for current QUP transfer
|
||||
+ */
|
||||
struct qup_i2c_block {
|
||||
- int count;
|
||||
- int pos;
|
||||
- int tx_tag_len;
|
||||
- int rx_tag_len;
|
||||
- int data_len;
|
||||
- u8 tags[6];
|
||||
+ int count;
|
||||
+ int pos;
|
||||
+ int tx_tag_len;
|
||||
+ int rx_tag_len;
|
||||
+ int data_len;
|
||||
+ int total_tx_len;
|
||||
+ int total_rx_len;
|
||||
+ int tx_fifo_free;
|
||||
+ int fifo_available;
|
||||
+ bool rx_bytes_read;
|
||||
+ bool is_tx_blk_mode;
|
||||
+ bool is_rx_blk_mode;
|
||||
+ u8 tags[6];
|
||||
};
|
||||
|
||||
struct qup_i2c_tag {
|
||||
@@ -186,6 +212,7 @@ struct qup_i2c_dev {
|
||||
|
||||
/* To check if this is the last msg */
|
||||
bool is_last;
|
||||
+ bool is_qup_v1;
|
||||
|
||||
/* To configure when bus is in run state */
|
||||
int config_run;
|
||||
@@ -202,11 +229,18 @@ struct qup_i2c_dev {
|
||||
struct qup_i2c_bam btx;
|
||||
|
||||
struct completion xfer;
|
||||
+ /* function to write data in tx fifo */
|
||||
+ void (*write_tx_fifo)(struct qup_i2c_dev *qup);
|
||||
+ /* function to read data from rx fifo */
|
||||
+ void (*read_rx_fifo)(struct qup_i2c_dev *qup);
|
||||
+ /* function to write tags in tx fifo for i2c read transfer */
|
||||
+ void (*write_rx_tags)(struct qup_i2c_dev *qup);
|
||||
};
|
||||
|
||||
static irqreturn_t qup_i2c_interrupt(int irq, void *dev)
|
||||
{
|
||||
struct qup_i2c_dev *qup = dev;
|
||||
+ struct qup_i2c_block *blk = &qup->blk;
|
||||
u32 bus_err;
|
||||
u32 qup_err;
|
||||
u32 opflags;
|
||||
@@ -253,12 +287,48 @@ static irqreturn_t qup_i2c_interrupt(int
|
||||
goto done;
|
||||
}
|
||||
|
||||
- if (opflags & QUP_IN_SVC_FLAG)
|
||||
- writel(QUP_IN_SVC_FLAG, qup->base + QUP_OPERATIONAL);
|
||||
+ if (!qup->is_qup_v1)
|
||||
+ goto done;
|
||||
|
||||
- if (opflags & QUP_OUT_SVC_FLAG)
|
||||
+ if (opflags & QUP_OUT_SVC_FLAG) {
|
||||
writel(QUP_OUT_SVC_FLAG, qup->base + QUP_OPERATIONAL);
|
||||
|
||||
+ if (opflags & OUT_BLOCK_WRITE_REQ) {
|
||||
+ blk->tx_fifo_free += qup->out_blk_sz;
|
||||
+ if (qup->msg->flags & I2C_M_RD)
|
||||
+ qup->write_rx_tags(qup);
|
||||
+ else
|
||||
+ qup->write_tx_fifo(qup);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (opflags & QUP_IN_SVC_FLAG) {
|
||||
+ writel(QUP_IN_SVC_FLAG, qup->base + QUP_OPERATIONAL);
|
||||
+
|
||||
+ if (!blk->is_rx_blk_mode) {
|
||||
+ blk->fifo_available += qup->in_fifo_sz;
|
||||
+ qup->read_rx_fifo(qup);
|
||||
+ } else if (opflags & IN_BLOCK_READ_REQ) {
|
||||
+ blk->fifo_available += qup->in_blk_sz;
|
||||
+ qup->read_rx_fifo(qup);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (qup->msg->flags & I2C_M_RD) {
|
||||
+ if (!blk->rx_bytes_read)
|
||||
+ return IRQ_HANDLED;
|
||||
+ } else {
|
||||
+ /*
|
||||
+ * Ideally, QUP_MAX_OUTPUT_DONE_FLAG should be checked
|
||||
+ * for FIFO mode also. But, QUP_MAX_OUTPUT_DONE_FLAG lags
|
||||
+ * behind QUP_OUTPUT_SERVICE_FLAG sometimes. The only reason
|
||||
+ * of interrupt for write message in FIFO mode is
|
||||
+ * QUP_MAX_OUTPUT_DONE_FLAG condition.
|
||||
+ */
|
||||
+ if (blk->is_tx_blk_mode && !(opflags & QUP_MX_OUTPUT_DONE))
|
||||
+ return IRQ_HANDLED;
|
||||
+ }
|
||||
+
|
||||
done:
|
||||
qup->qup_err = qup_err;
|
||||
qup->bus_err = bus_err;
|
||||
@@ -324,6 +394,28 @@ static int qup_i2c_change_state(struct q
|
||||
return 0;
|
||||
}
|
||||
|
||||
+/* Check if I2C bus returns to IDLE state */
|
||||
+static int qup_i2c_bus_active(struct qup_i2c_dev *qup, int len)
|
||||
+{
|
||||
+ unsigned long timeout;
|
||||
+ u32 status;
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ timeout = jiffies + len * 4;
|
||||
+ for (;;) {
|
||||
+ status = readl(qup->base + QUP_I2C_STATUS);
|
||||
+ if (!(status & I2C_STATUS_BUS_ACTIVE))
|
||||
+ break;
|
||||
+
|
||||
+ if (time_after(jiffies, timeout))
|
||||
+ ret = -ETIMEDOUT;
|
||||
+
|
||||
+ usleep_range(len, len * 2);
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* qup_i2c_wait_ready - wait for a give number of bytes in tx/rx path
|
||||
* @qup: The qup_i2c_dev device
|
||||
@@ -394,23 +486,6 @@ static void qup_i2c_set_write_mode_v2(st
|
||||
}
|
||||
}
|
||||
|
||||
-static void qup_i2c_set_write_mode(struct qup_i2c_dev *qup, struct i2c_msg *msg)
|
||||
-{
|
||||
- /* Number of entries to shift out, including the start */
|
||||
- int total = msg->len + 1;
|
||||
-
|
||||
- if (total < qup->out_fifo_sz) {
|
||||
- /* FIFO mode */
|
||||
- writel(QUP_REPACK_EN, qup->base + QUP_IO_MODE);
|
||||
- writel(total, qup->base + QUP_MX_WRITE_CNT);
|
||||
- } else {
|
||||
- /* BLOCK mode (transfer data on chunks) */
|
||||
- writel(QUP_OUTPUT_BLK_MODE | QUP_REPACK_EN,
|
||||
- qup->base + QUP_IO_MODE);
|
||||
- writel(total, qup->base + QUP_MX_OUTPUT_CNT);
|
||||
- }
|
||||
-}
|
||||
-
|
||||
static int check_for_fifo_space(struct qup_i2c_dev *qup)
|
||||
{
|
||||
int ret;
|
||||
@@ -443,28 +518,25 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
-static int qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg)
|
||||
+static void qup_i2c_write_tx_fifo_v1(struct qup_i2c_dev *qup)
|
||||
{
|
||||
+ struct qup_i2c_block *blk = &qup->blk;
|
||||
+ struct i2c_msg *msg = qup->msg;
|
||||
u32 addr = msg->addr << 1;
|
||||
u32 qup_tag;
|
||||
int idx;
|
||||
u32 val;
|
||||
- int ret = 0;
|
||||
|
||||
if (qup->pos == 0) {
|
||||
val = QUP_TAG_START | addr;
|
||||
idx = 1;
|
||||
+ blk->tx_fifo_free--;
|
||||
} else {
|
||||
val = 0;
|
||||
idx = 0;
|
||||
}
|
||||
|
||||
- while (qup->pos < msg->len) {
|
||||
- /* Check that there's space in the FIFO for our pair */
|
||||
- ret = check_for_fifo_space(qup);
|
||||
- if (ret)
|
||||
- return ret;
|
||||
-
|
||||
+ while (blk->tx_fifo_free && qup->pos < msg->len) {
|
||||
if (qup->pos == msg->len - 1)
|
||||
qup_tag = QUP_TAG_STOP;
|
||||
else
|
||||
@@ -481,11 +553,8 @@ static int qup_i2c_issue_write(struct qu
|
||||
|
||||
qup->pos++;
|
||||
idx++;
|
||||
+ blk->tx_fifo_free--;
|
||||
}
|
||||
-
|
||||
- ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
|
||||
-
|
||||
- return ret;
|
||||
}
|
||||
|
||||
static void qup_i2c_set_blk_data(struct qup_i2c_dev *qup,
|
||||
@@ -1006,64 +1075,6 @@ err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
-static int qup_i2c_write_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
|
||||
-{
|
||||
- int ret;
|
||||
-
|
||||
- qup->msg = msg;
|
||||
- qup->pos = 0;
|
||||
-
|
||||
- enable_irq(qup->irq);
|
||||
-
|
||||
- qup_i2c_set_write_mode(qup, msg);
|
||||
-
|
||||
- ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
|
||||
- if (ret)
|
||||
- goto err;
|
||||
-
|
||||
- writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
|
||||
-
|
||||
- do {
|
||||
- ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE);
|
||||
- if (ret)
|
||||
- goto err;
|
||||
-
|
||||
- ret = qup_i2c_issue_write(qup, msg);
|
||||
- if (ret)
|
||||
- goto err;
|
||||
-
|
||||
- ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
|
||||
- if (ret)
|
||||
- goto err;
|
||||
-
|
||||
- ret = qup_i2c_wait_for_complete(qup, msg);
|
||||
- if (ret)
|
||||
- goto err;
|
||||
- } while (qup->pos < msg->len);
|
||||
-
|
||||
- /* Wait for the outstanding data in the fifo to drain */
|
||||
- ret = qup_i2c_wait_ready(qup, QUP_OUT_NOT_EMPTY, RESET_BIT, ONE_BYTE);
|
||||
-err:
|
||||
- disable_irq(qup->irq);
|
||||
- qup->msg = NULL;
|
||||
-
|
||||
- return ret;
|
||||
-}
|
||||
-
|
||||
-static void qup_i2c_set_read_mode(struct qup_i2c_dev *qup, int len)
|
||||
-{
|
||||
- if (len < qup->in_fifo_sz) {
|
||||
- /* FIFO mode */
|
||||
- writel(QUP_REPACK_EN, qup->base + QUP_IO_MODE);
|
||||
- writel(len, qup->base + QUP_MX_READ_CNT);
|
||||
- } else {
|
||||
- /* BLOCK mode (transfer data on chunks) */
|
||||
- writel(QUP_INPUT_BLK_MODE | QUP_REPACK_EN,
|
||||
- qup->base + QUP_IO_MODE);
|
||||
- writel(len, qup->base + QUP_MX_INPUT_CNT);
|
||||
- }
|
||||
-}
|
||||
-
|
||||
static void qup_i2c_set_read_mode_v2(struct qup_i2c_dev *qup, int len)
|
||||
{
|
||||
int tx_len = qup->blk.tx_tag_len;
|
||||
@@ -1086,44 +1097,27 @@ static void qup_i2c_set_read_mode_v2(str
|
||||
}
|
||||
}
|
||||
|
||||
-static void qup_i2c_issue_read(struct qup_i2c_dev *qup, struct i2c_msg *msg)
|
||||
-{
|
||||
- u32 addr, len, val;
|
||||
-
|
||||
- addr = i2c_8bit_addr_from_msg(msg);
|
||||
-
|
||||
- /* 0 is used to specify a length 256 (QUP_READ_LIMIT) */
|
||||
- len = (msg->len == QUP_READ_LIMIT) ? 0 : msg->len;
|
||||
-
|
||||
- val = ((QUP_TAG_REC | len) << QUP_MSW_SHIFT) | QUP_TAG_START | addr;
|
||||
- writel(val, qup->base + QUP_OUT_FIFO_BASE);
|
||||
-}
|
||||
-
|
||||
-
|
||||
-static int qup_i2c_read_fifo(struct qup_i2c_dev *qup, struct i2c_msg *msg)
|
||||
+static void qup_i2c_read_rx_fifo_v1(struct qup_i2c_dev *qup)
|
||||
{
|
||||
+ struct qup_i2c_block *blk = &qup->blk;
|
||||
+ struct i2c_msg *msg = qup->msg;
|
||||
u32 val = 0;
|
||||
- int idx;
|
||||
- int ret = 0;
|
||||
+ int idx = 0;
|
||||
|
||||
- for (idx = 0; qup->pos < msg->len; idx++) {
|
||||
+ while (blk->fifo_available && qup->pos < msg->len) {
|
||||
if ((idx & 1) == 0) {
|
||||
- /* Check that FIFO have data */
|
||||
- ret = qup_i2c_wait_ready(qup, QUP_IN_NOT_EMPTY,
|
||||
- SET_BIT, 4 * ONE_BYTE);
|
||||
- if (ret)
|
||||
- return ret;
|
||||
-
|
||||
/* Reading 2 words at time */
|
||||
val = readl(qup->base + QUP_IN_FIFO_BASE);
|
||||
-
|
||||
msg->buf[qup->pos++] = val & 0xFF;
|
||||
} else {
|
||||
msg->buf[qup->pos++] = val >> QUP_MSW_SHIFT;
|
||||
}
|
||||
+ idx++;
|
||||
+ blk->fifo_available--;
|
||||
}
|
||||
|
||||
- return ret;
|
||||
+ if (qup->pos == msg->len)
|
||||
+ blk->rx_bytes_read = true;
|
||||
}
|
||||
|
||||
static int qup_i2c_read_fifo_v2(struct qup_i2c_dev *qup,
|
||||
@@ -1224,49 +1218,130 @@ err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
-static int qup_i2c_read_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
|
||||
+static void qup_i2c_write_rx_tags_v1(struct qup_i2c_dev *qup)
|
||||
{
|
||||
- int ret;
|
||||
+ struct i2c_msg *msg = qup->msg;
|
||||
+ u32 addr, len, val;
|
||||
|
||||
- qup->msg = msg;
|
||||
- qup->pos = 0;
|
||||
+ addr = i2c_8bit_addr_from_msg(msg);
|
||||
|
||||
- enable_irq(qup->irq);
|
||||
- qup_i2c_set_read_mode(qup, msg->len);
|
||||
+ /* 0 is used to specify a length 256 (QUP_READ_LIMIT) */
|
||||
+ len = (msg->len == QUP_READ_LIMIT) ? 0 : msg->len;
|
||||
+
|
||||
+ val = ((QUP_TAG_REC | len) << QUP_MSW_SHIFT) | QUP_TAG_START | addr;
|
||||
+ writel(val, qup->base + QUP_OUT_FIFO_BASE);
|
||||
+}
|
||||
+
|
||||
+static void qup_i2c_conf_v1(struct qup_i2c_dev *qup)
|
||||
+{
|
||||
+ struct qup_i2c_block *blk = &qup->blk;
|
||||
+ u32 qup_config = I2C_MINI_CORE | I2C_N_VAL;
|
||||
+ u32 io_mode = QUP_REPACK_EN;
|
||||
+
|
||||
+ blk->is_tx_blk_mode =
|
||||
+ blk->total_tx_len > qup->out_fifo_sz ? true : false;
|
||||
+ blk->is_rx_blk_mode =
|
||||
+ blk->total_rx_len > qup->in_fifo_sz ? true : false;
|
||||
+
|
||||
+ if (blk->is_tx_blk_mode) {
|
||||
+ io_mode |= QUP_OUTPUT_BLK_MODE;
|
||||
+ writel(0, qup->base + QUP_MX_WRITE_CNT);
|
||||
+ writel(blk->total_tx_len, qup->base + QUP_MX_OUTPUT_CNT);
|
||||
+ } else {
|
||||
+ writel(0, qup->base + QUP_MX_OUTPUT_CNT);
|
||||
+ writel(blk->total_tx_len, qup->base + QUP_MX_WRITE_CNT);
|
||||
+ }
|
||||
+
|
||||
+ if (blk->total_rx_len) {
|
||||
+ if (blk->is_rx_blk_mode) {
|
||||
+ io_mode |= QUP_INPUT_BLK_MODE;
|
||||
+ writel(0, qup->base + QUP_MX_READ_CNT);
|
||||
+ writel(blk->total_rx_len, qup->base + QUP_MX_INPUT_CNT);
|
||||
+ } else {
|
||||
+ writel(0, qup->base + QUP_MX_INPUT_CNT);
|
||||
+ writel(blk->total_rx_len, qup->base + QUP_MX_READ_CNT);
|
||||
+ }
|
||||
+ } else {
|
||||
+ qup_config |= QUP_NO_INPUT;
|
||||
+ }
|
||||
+
|
||||
+ writel(qup_config, qup->base + QUP_CONFIG);
|
||||
+ writel(io_mode, qup->base + QUP_IO_MODE);
|
||||
+}
|
||||
|
||||
+static void qup_i2c_clear_blk_v1(struct qup_i2c_block *blk)
|
||||
+{
|
||||
+ blk->tx_fifo_free = 0;
|
||||
+ blk->fifo_available = 0;
|
||||
+ blk->rx_bytes_read = false;
|
||||
+}
|
||||
+
|
||||
+static int qup_i2c_conf_xfer_v1(struct qup_i2c_dev *qup, bool is_rx)
|
||||
+{
|
||||
+ struct qup_i2c_block *blk = &qup->blk;
|
||||
+ int ret;
|
||||
+
|
||||
+ qup_i2c_clear_blk_v1(blk);
|
||||
+ qup_i2c_conf_v1(qup);
|
||||
ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
|
||||
if (ret)
|
||||
- goto err;
|
||||
+ return ret;
|
||||
|
||||
writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
|
||||
|
||||
ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE);
|
||||
if (ret)
|
||||
- goto err;
|
||||
+ return ret;
|
||||
+
|
||||
+ reinit_completion(&qup->xfer);
|
||||
+ enable_irq(qup->irq);
|
||||
+ if (!blk->is_tx_blk_mode) {
|
||||
+ blk->tx_fifo_free = qup->out_fifo_sz;
|
||||
|
||||
- qup_i2c_issue_read(qup, msg);
|
||||
+ if (is_rx)
|
||||
+ qup_i2c_write_rx_tags_v1(qup);
|
||||
+ else
|
||||
+ qup_i2c_write_tx_fifo_v1(qup);
|
||||
+ }
|
||||
|
||||
ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
- do {
|
||||
- ret = qup_i2c_wait_for_complete(qup, msg);
|
||||
- if (ret)
|
||||
- goto err;
|
||||
+ ret = qup_i2c_wait_for_complete(qup, qup->msg);
|
||||
+ if (ret)
|
||||
+ goto err;
|
||||
|
||||
- ret = qup_i2c_read_fifo(qup, msg);
|
||||
- if (ret)
|
||||
- goto err;
|
||||
- } while (qup->pos < msg->len);
|
||||
+ ret = qup_i2c_bus_active(qup, ONE_BYTE);
|
||||
|
||||
err:
|
||||
disable_irq(qup->irq);
|
||||
- qup->msg = NULL;
|
||||
-
|
||||
return ret;
|
||||
}
|
||||
|
||||
+static int qup_i2c_write_one(struct qup_i2c_dev *qup)
|
||||
+{
|
||||
+ struct i2c_msg *msg = qup->msg;
|
||||
+ struct qup_i2c_block *blk = &qup->blk;
|
||||
+
|
||||
+ qup->pos = 0;
|
||||
+ blk->total_tx_len = msg->len + 1;
|
||||
+ blk->total_rx_len = 0;
|
||||
+
|
||||
+ return qup_i2c_conf_xfer_v1(qup, false);
|
||||
+}
|
||||
+
|
||||
+static int qup_i2c_read_one(struct qup_i2c_dev *qup)
|
||||
+{
|
||||
+ struct qup_i2c_block *blk = &qup->blk;
|
||||
+
|
||||
+ qup->pos = 0;
|
||||
+ blk->total_tx_len = 2;
|
||||
+ blk->total_rx_len = qup->msg->len;
|
||||
+
|
||||
+ return qup_i2c_conf_xfer_v1(qup, true);
|
||||
+}
|
||||
+
|
||||
static int qup_i2c_xfer(struct i2c_adapter *adap,
|
||||
struct i2c_msg msgs[],
|
||||
int num)
|
||||
@@ -1305,10 +1380,11 @@ static int qup_i2c_xfer(struct i2c_adapt
|
||||
goto out;
|
||||
}
|
||||
|
||||
+ qup->msg = &msgs[idx];
|
||||
if (msgs[idx].flags & I2C_M_RD)
|
||||
- ret = qup_i2c_read_one(qup, &msgs[idx]);
|
||||
+ ret = qup_i2c_read_one(qup);
|
||||
else
|
||||
- ret = qup_i2c_write_one(qup, &msgs[idx]);
|
||||
+ ret = qup_i2c_write_one(qup);
|
||||
|
||||
if (ret)
|
||||
break;
|
||||
@@ -1487,6 +1563,10 @@ static int qup_i2c_probe(struct platform
|
||||
if (of_device_is_compatible(pdev->dev.of_node, "qcom,i2c-qup-v1.1.1")) {
|
||||
qup->adap.algo = &qup_i2c_algo;
|
||||
qup->adap.quirks = &qup_i2c_quirks;
|
||||
+ qup->is_qup_v1 = true;
|
||||
+ qup->write_tx_fifo = qup_i2c_write_tx_fifo_v1;
|
||||
+ qup->read_rx_fifo = qup_i2c_read_rx_fifo_v1;
|
||||
+ qup->write_rx_tags = qup_i2c_write_rx_tags_v1;
|
||||
} else {
|
||||
qup->adap.algo = &qup_i2c_algo_v2;
|
||||
ret = qup_i2c_req_dma(qup);
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,29 +0,0 @@
|
||||
From 09f145f417a5d64d6b8d4476699dfb0eccc6c784 Mon Sep 17 00:00:00 2001
|
||||
From: Abhishek Sahu <absahu@codeaurora.org>
|
||||
Date: Tue, 7 May 2019 10:14:05 +0300
|
||||
Subject: [PATCH] ipq40xx: fix high resolution timer
|
||||
|
||||
Cherry-picked from CAF QSDK repo.
|
||||
Original commit message:
|
||||
The kernel is failing in switching the timer for high resolution
|
||||
mode and clock source operates in 10ms resolution. The always-on
|
||||
property needs to be given for timer device tree node to make
|
||||
clock source working in 1ns resolution.
|
||||
|
||||
Change-Id: I7c00b3c74d97c2a30ac9f05e18b511a0550fd459
|
||||
Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
|
||||
Signed-off-by: Pavel Kubelun <be.dissent@gmail.com>
|
||||
---
|
||||
arch/arm/boot/dts/qcom-ipq4019.dtsi | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
--- a/arch/arm/boot/dts/qcom-ipq4019.dtsi
|
||||
+++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi
|
||||
@@ -167,6 +167,7 @@
|
||||
<1 4 0xf08>,
|
||||
<1 1 0xf08>;
|
||||
clock-frequency = <48000000>;
|
||||
+ always-on;
|
||||
};
|
||||
|
||||
soc {
|
||||
@ -1,62 +0,0 @@
|
||||
--- a/drivers/mtd/spi-nor/spi-nor.c
|
||||
+++ b/drivers/mtd/spi-nor/spi-nor.c
|
||||
@@ -1037,6 +1037,7 @@ static const struct flash_info spi_nor_i
|
||||
{ "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) },
|
||||
{ "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) },
|
||||
{ "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
|
||||
+ { "mx25l25635f", INFO(0xc22019, 0, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
|
||||
{ "mx25u25635f", INFO(0xc22539, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_4B_OPCODES) },
|
||||
{ "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) },
|
||||
{ "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
|
||||
@@ -1209,11 +1210,12 @@ static const struct flash_info spi_nor_i
|
||||
{ },
|
||||
};
|
||||
|
||||
-static const struct flash_info *spi_nor_read_id(struct spi_nor *nor)
|
||||
+static const struct flash_info *spi_nor_read_id(struct spi_nor *nor,
|
||||
+ const char *name)
|
||||
{
|
||||
int tmp;
|
||||
u8 id[SPI_NOR_MAX_ID_LEN];
|
||||
- const struct flash_info *info;
|
||||
+ const struct flash_info *info, *first_match = NULL;
|
||||
|
||||
tmp = nor->read_reg(nor, SPINOR_OP_RDID, id, SPI_NOR_MAX_ID_LEN);
|
||||
if (tmp < 0) {
|
||||
@@ -1224,10 +1226,16 @@ static const struct flash_info *spi_nor_
|
||||
for (tmp = 0; tmp < ARRAY_SIZE(spi_nor_ids) - 1; tmp++) {
|
||||
info = &spi_nor_ids[tmp];
|
||||
if (info->id_len) {
|
||||
- if (!memcmp(info->id, id, info->id_len))
|
||||
- return &spi_nor_ids[tmp];
|
||||
+ if (!memcmp(info->id, id, info->id_len)) {
|
||||
+ if (!name || !strcmp(name, info->name))
|
||||
+ return info;
|
||||
+ if (!first_match)
|
||||
+ first_match = info;
|
||||
+ }
|
||||
}
|
||||
}
|
||||
+ if (first_match)
|
||||
+ return first_match;
|
||||
dev_err(nor->dev, "unrecognized JEDEC id bytes: %02x, %02x, %02x\n",
|
||||
id[0], id[1], id[2]);
|
||||
return ERR_PTR(-ENODEV);
|
||||
@@ -2687,7 +2695,7 @@ int spi_nor_scan(struct spi_nor *nor, co
|
||||
info = spi_nor_match_id(name);
|
||||
/* Try to auto-detect if chip name wasn't specified or not found */
|
||||
if (!info)
|
||||
- info = spi_nor_read_id(nor);
|
||||
+ info = spi_nor_read_id(nor, NULL);
|
||||
if (IS_ERR_OR_NULL(info))
|
||||
return -ENOENT;
|
||||
|
||||
@@ -2698,7 +2706,7 @@ int spi_nor_scan(struct spi_nor *nor, co
|
||||
if (name && info->id_len) {
|
||||
const struct flash_info *jinfo;
|
||||
|
||||
- jinfo = spi_nor_read_id(nor);
|
||||
+ jinfo = spi_nor_read_id(nor, name);
|
||||
if (IS_ERR(jinfo)) {
|
||||
return PTR_ERR(jinfo);
|
||||
} else if (jinfo != info) {
|
||||
@ -1,10 +0,0 @@
|
||||
--- a/drivers/mtd/spi-nor/spi-nor.c
|
||||
+++ b/drivers/mtd/spi-nor/spi-nor.c
|
||||
@@ -955,6 +955,7 @@ static const struct flash_info spi_nor_i
|
||||
{ "en25p64", INFO(0x1c2017, 0, 64 * 1024, 128, 0) },
|
||||
{ "en25q64", INFO(0x1c3017, 0, 64 * 1024, 128, SECT_4K) },
|
||||
{ "en25q128", INFO(0x1c3018, 0, 64 * 1024, 256, SECT_4K) },
|
||||
+ { "en25qh16", INFO(0x1c7015, 0, 64 * 1024, 32, SECT_4K | SPI_NOR_DUAL_READ) },
|
||||
{ "en25qh32", INFO(0x1c7016, 0, 64 * 1024, 64, 0) },
|
||||
{ "en25qh64", INFO(0x1c7017, 0, 64 * 1024, 128, 0) },
|
||||
{ "en25qh128", INFO(0x1c7018, 0, 64 * 1024, 256, 0) },
|
||||
@ -1,11 +0,0 @@
|
||||
--- a/drivers/mmc/host/sdhci-msm.c
|
||||
+++ b/drivers/mmc/host/sdhci-msm.c
|
||||
@@ -1171,7 +1171,7 @@ MODULE_DEVICE_TABLE(of, sdhci_msm_dt_mat
|
||||
|
||||
static const struct sdhci_ops sdhci_msm_ops = {
|
||||
.reset = sdhci_reset,
|
||||
- .set_clock = sdhci_msm_set_clock,
|
||||
+ .set_clock = sdhci_set_clock,
|
||||
.get_min_clock = sdhci_msm_get_min_clock,
|
||||
.get_max_clock = sdhci_msm_get_max_clock,
|
||||
.set_bus_width = sdhci_set_bus_width,
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,52 +0,0 @@
|
||||
From 09ed737593f71bcca08a537a6c15264a1a6add08 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Lamparter <chunkeey@gmail.com>
|
||||
Date: Sun, 20 Nov 2016 01:10:33 +0100
|
||||
Subject: [PATCH] dts: ipq4019: add mdio node for ethernet
|
||||
|
||||
This patch adds the mdio device-tree node.
|
||||
This is where the switch is connected to, so it's needed
|
||||
for the ethernet interfaces.
|
||||
|
||||
Note: The driver isn't anywhere close to be upstream,
|
||||
so the info might change.
|
||||
---
|
||||
arch/arm/boot/dts/qcom-ipq4019.dtsi | 28 ++++++++++++++++++++++++++++
|
||||
1 file changed, 28 insertions(+)
|
||||
|
||||
--- a/arch/arm/boot/dts/qcom-ipq4019.dtsi
|
||||
+++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi
|
||||
@@ -567,6 +567,34 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
+ mdio@90000 {
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
+ compatible = "qcom,ipq4019-mdio";
|
||||
+ reg = <0x90000 0x64>;
|
||||
+ status = "disabled";
|
||||
+
|
||||
+ ethernet-phy@0 {
|
||||
+ reg = <0>;
|
||||
+ };
|
||||
+
|
||||
+ ethernet-phy@1 {
|
||||
+ reg = <1>;
|
||||
+ };
|
||||
+
|
||||
+ ethernet-phy@2 {
|
||||
+ reg = <2>;
|
||||
+ };
|
||||
+
|
||||
+ ethernet-phy@3 {
|
||||
+ reg = <3>;
|
||||
+ };
|
||||
+
|
||||
+ ethernet-phy@4 {
|
||||
+ reg = <4>;
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
usb3_ss_phy: ssphy@9a000 {
|
||||
compatible = "qcom,usb-ss-ipq4019-phy";
|
||||
#phy-cells = <0>;
|
||||
@ -1,46 +0,0 @@
|
||||
From 9deeec35dd3b628b95624e41d4e04acf728991ba Mon Sep 17 00:00:00 2001
|
||||
From: Christian Lamparter <chunkeey@gmail.com>
|
||||
Date: Sun, 20 Nov 2016 02:20:54 +0100
|
||||
Subject: [PATCH] dts: ipq4019: add PHY/switch nodes
|
||||
|
||||
This patch adds both the "qcom,ess-switch" and "qcom,ess-psgmii"
|
||||
nodes which are needed for the ar40xx.c driver to initialize the
|
||||
switch.
|
||||
|
||||
Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
|
||||
---
|
||||
arch/arm/boot/dts/qcom-ipq4019.dtsi | 23 +++++++++++++++++++++++
|
||||
1 file changed, 23 insertions(+)
|
||||
|
||||
--- a/arch/arm/boot/dts/qcom-ipq4019.dtsi
|
||||
+++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi
|
||||
@@ -595,6 +595,29 @@
|
||||
};
|
||||
};
|
||||
|
||||
+ ess-switch@c000000 {
|
||||
+ compatible = "qcom,ess-switch";
|
||||
+ reg = <0xc000000 0x80000>;
|
||||
+ switch_access_mode = "local bus";
|
||||
+ resets = <&gcc ESS_RESET>;
|
||||
+ reset-names = "ess_rst";
|
||||
+ clocks = <&gcc GCC_ESS_CLK>;
|
||||
+ clock-names = "ess_clk";
|
||||
+ switch_cpu_bmp = <0x1>;
|
||||
+ switch_lan_bmp = <0x1e>;
|
||||
+ switch_wan_bmp = <0x20>;
|
||||
+ switch_mac_mode = <0>; /* PORT_WRAPPER_PSGMII */
|
||||
+ switch_initvlas = <0x7c 0x54>;
|
||||
+ status = "disabled";
|
||||
+ };
|
||||
+
|
||||
+ ess-psgmii@98000 {
|
||||
+ compatible = "qcom,ess-psgmii";
|
||||
+ reg = <0x98000 0x800>;
|
||||
+ psgmii_access_mode = "local bus";
|
||||
+ status = "disabled";
|
||||
+ };
|
||||
+
|
||||
usb3_ss_phy: ssphy@9a000 {
|
||||
compatible = "qcom,usb-ss-ipq4019-phy";
|
||||
#phy-cells = <0>;
|
||||
@ -1,53 +0,0 @@
|
||||
From 7c129254adb1093d10a62ed7bf7b956fcc6ffe34 Mon Sep 17 00:00:00 2001
|
||||
From: Rakesh Nair <ranair@codeaurora.org>
|
||||
Date: Wed, 20 Jul 2016 15:02:01 +0530
|
||||
Subject: [PATCH] net: IPQ4019 needs rfs/vlan_tag callbacks in
|
||||
netdev_ops
|
||||
|
||||
Add callback support to get default vlan tag and register
|
||||
receive flow steering filter.
|
||||
|
||||
Used by IPQ4019 ess-edma driver.
|
||||
|
||||
BUG=chrome-os-partner:33096
|
||||
TEST=none
|
||||
|
||||
Change-Id: I266070e4a0fbe4a0d9966fe79a71e50ec4f26c75
|
||||
Signed-off-by: Rakesh Nair <ranair@codeaurora.org>
|
||||
Reviewed-on: https://chromium-review.googlesource.com/362203
|
||||
Commit-Ready: Grant Grundler <grundler@chromium.org>
|
||||
Tested-by: Grant Grundler <grundler@chromium.org>
|
||||
Reviewed-by: Grant Grundler <grundler@chromium.org>
|
||||
---
|
||||
include/linux/netdevice.h | 13 +++++++++++++
|
||||
1 file changed, 13 insertions(+)
|
||||
|
||||
--- a/include/linux/netdevice.h
|
||||
+++ b/include/linux/netdevice.h
|
||||
@@ -716,6 +716,16 @@ struct xps_map {
|
||||
#define XPS_MIN_MAP_ALLOC ((L1_CACHE_ALIGN(offsetof(struct xps_map, queues[1])) \
|
||||
- sizeof(struct xps_map)) / sizeof(u16))
|
||||
|
||||
+#ifdef CONFIG_RFS_ACCEL
|
||||
+typedef int (*set_rfs_filter_callback_t)(struct net_device *dev,
|
||||
+ __be32 src,
|
||||
+ __be32 dst,
|
||||
+ __be16 sport,
|
||||
+ __be16 dport,
|
||||
+ u8 proto,
|
||||
+ u16 rxq_index,
|
||||
+ u32 action);
|
||||
+#endif
|
||||
/*
|
||||
* This structure holds all XPS maps for device. Maps are indexed by CPU.
|
||||
*/
|
||||
@@ -1261,6 +1271,9 @@ struct net_device_ops {
|
||||
const struct sk_buff *skb,
|
||||
u16 rxq_index,
|
||||
u32 flow_id);
|
||||
+ int (*ndo_register_rfs_filter)(struct net_device *dev,
|
||||
+ set_rfs_filter_callback_t set_filter);
|
||||
+ int (*ndo_get_default_vlan_tag)(struct net_device *net);
|
||||
#endif
|
||||
int (*ndo_add_slave)(struct net_device *dev,
|
||||
struct net_device *slave_dev);
|
||||
@ -1,23 +0,0 @@
|
||||
--- a/drivers/net/phy/ar40xx.c
|
||||
+++ b/drivers/net/phy/ar40xx.c
|
||||
@@ -2022,6 +2022,12 @@ static int ar40xx_probe(struct platform_
|
||||
/* register switch */
|
||||
swdev = &priv->dev;
|
||||
|
||||
+ if (priv->mii_bus == NULL) {
|
||||
+ dev_err(&pdev->dev, "Probe failed - Missing PHYs!\n");
|
||||
+ ret = -ENODEV;
|
||||
+ goto err_missing_phy;
|
||||
+ }
|
||||
+
|
||||
swdev->alias = dev_name(&priv->mii_bus->dev);
|
||||
|
||||
swdev->cpu_port = AR40XX_PORT_CPU;
|
||||
@@ -2053,6 +2059,7 @@ err_unregister_switch:
|
||||
unregister_switch(&priv->dev);
|
||||
err_unregister_phy:
|
||||
phy_driver_unregister(&ar40xx_phy_driver);
|
||||
+err_missing_phy:
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
return ret;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,92 +0,0 @@
|
||||
From c611d3780fa101662a822d10acf8feb04ca97409 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Lamparter <chunkeey@gmail.com>
|
||||
Date: Sun, 20 Nov 2016 01:01:10 +0100
|
||||
Subject: [PATCH] dts: ipq4019: add ethernet essedma node
|
||||
|
||||
This patch adds the device-tree node for the ethernet
|
||||
interfaces.
|
||||
|
||||
Note: The driver isn't anywhere close to be upstream,
|
||||
so the info might change.
|
||||
|
||||
Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
|
||||
---
|
||||
arch/arm/boot/dts/qcom-ipq4019.dtsi | 60 +++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 60 insertions(+)
|
||||
|
||||
--- a/arch/arm/boot/dts/qcom-ipq4019.dtsi
|
||||
+++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi
|
||||
@@ -44,6 +44,8 @@
|
||||
spi1 = &blsp1_spi2;
|
||||
i2c0 = &blsp1_i2c3;
|
||||
i2c1 = &blsp1_i2c4;
|
||||
+ ethernet0 = &gmac0;
|
||||
+ ethernet1 = &gmac1;
|
||||
};
|
||||
|
||||
cpus {
|
||||
@@ -618,6 +620,64 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
+ edma@c080000 {
|
||||
+ compatible = "qcom,ess-edma";
|
||||
+ reg = <0xc080000 0x8000>;
|
||||
+ qcom,page-mode = <0>;
|
||||
+ qcom,rx_head_buf_size = <1540>;
|
||||
+ qcom,mdio_supported;
|
||||
+ qcom,poll_required = <1>;
|
||||
+ qcom,num_gmac = <2>;
|
||||
+ interrupts = <0 65 IRQ_TYPE_EDGE_RISING
|
||||
+ 0 66 IRQ_TYPE_EDGE_RISING
|
||||
+ 0 67 IRQ_TYPE_EDGE_RISING
|
||||
+ 0 68 IRQ_TYPE_EDGE_RISING
|
||||
+ 0 69 IRQ_TYPE_EDGE_RISING
|
||||
+ 0 70 IRQ_TYPE_EDGE_RISING
|
||||
+ 0 71 IRQ_TYPE_EDGE_RISING
|
||||
+ 0 72 IRQ_TYPE_EDGE_RISING
|
||||
+ 0 73 IRQ_TYPE_EDGE_RISING
|
||||
+ 0 74 IRQ_TYPE_EDGE_RISING
|
||||
+ 0 75 IRQ_TYPE_EDGE_RISING
|
||||
+ 0 76 IRQ_TYPE_EDGE_RISING
|
||||
+ 0 77 IRQ_TYPE_EDGE_RISING
|
||||
+ 0 78 IRQ_TYPE_EDGE_RISING
|
||||
+ 0 79 IRQ_TYPE_EDGE_RISING
|
||||
+ 0 80 IRQ_TYPE_EDGE_RISING
|
||||
+ 0 240 IRQ_TYPE_EDGE_RISING
|
||||
+ 0 241 IRQ_TYPE_EDGE_RISING
|
||||
+ 0 242 IRQ_TYPE_EDGE_RISING
|
||||
+ 0 243 IRQ_TYPE_EDGE_RISING
|
||||
+ 0 244 IRQ_TYPE_EDGE_RISING
|
||||
+ 0 245 IRQ_TYPE_EDGE_RISING
|
||||
+ 0 246 IRQ_TYPE_EDGE_RISING
|
||||
+ 0 247 IRQ_TYPE_EDGE_RISING
|
||||
+ 0 248 IRQ_TYPE_EDGE_RISING
|
||||
+ 0 249 IRQ_TYPE_EDGE_RISING
|
||||
+ 0 250 IRQ_TYPE_EDGE_RISING
|
||||
+ 0 251 IRQ_TYPE_EDGE_RISING
|
||||
+ 0 252 IRQ_TYPE_EDGE_RISING
|
||||
+ 0 253 IRQ_TYPE_EDGE_RISING
|
||||
+ 0 254 IRQ_TYPE_EDGE_RISING
|
||||
+ 0 255 IRQ_TYPE_EDGE_RISING>;
|
||||
+
|
||||
+ status = "disabled";
|
||||
+
|
||||
+ gmac0: gmac0 {
|
||||
+ local-mac-address = [00 00 00 00 00 00];
|
||||
+ vlan_tag = <1 0x1f>;
|
||||
+ };
|
||||
+
|
||||
+ gmac1: gmac1 {
|
||||
+ local-mac-address = [00 00 00 00 00 00];
|
||||
+ qcom,phy_mdio_addr = <4>;
|
||||
+ qcom,poll_required = <1>;
|
||||
+ qcom,forced_speed = <1000>;
|
||||
+ qcom,forced_duplex = <1>;
|
||||
+ vlan_tag = <2 0x20>;
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
usb3_ss_phy: ssphy@9a000 {
|
||||
compatible = "qcom,usb-ss-ipq4019-phy";
|
||||
#phy-cells = <0>;
|
||||
@ -1,340 +0,0 @@
|
||||
--- a/drivers/net/ethernet/qualcomm/essedma/edma_axi.c
|
||||
+++ b/drivers/net/ethernet/qualcomm/essedma/edma_axi.c
|
||||
@@ -17,6 +17,11 @@
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_net.h>
|
||||
#include <linux/timer.h>
|
||||
+#include <linux/of_platform.h>
|
||||
+#include <linux/of_address.h>
|
||||
+#include <linux/clk.h>
|
||||
+#include <linux/string.h>
|
||||
+#include <linux/reset.h>
|
||||
#include "edma.h"
|
||||
#include "ess_edma.h"
|
||||
|
||||
@@ -83,7 +88,103 @@ void edma_read_reg(u16 reg_addr, volatil
|
||||
*reg_value = readl((void __iomem *)(edma_hw_addr + reg_addr));
|
||||
}
|
||||
|
||||
-/* edma_change_tx_coalesce()
|
||||
+static void ess_write_reg(struct edma_common_info *edma, u16 reg_addr, u32 reg_value)
|
||||
+{
|
||||
+ writel(reg_value, ((void __iomem *)
|
||||
+ ((unsigned long)edma->ess_hw_addr + reg_addr)));
|
||||
+}
|
||||
+
|
||||
+static void ess_read_reg(struct edma_common_info *edma, u16 reg_addr,
|
||||
+ volatile u32 *reg_value)
|
||||
+{
|
||||
+ *reg_value = readl((void __iomem *)
|
||||
+ ((unsigned long)edma->ess_hw_addr + reg_addr));
|
||||
+}
|
||||
+
|
||||
+static int ess_reset(struct edma_common_info *edma)
|
||||
+{
|
||||
+ struct device_node *switch_node = NULL;
|
||||
+ struct reset_control *ess_rst;
|
||||
+ u32 regval;
|
||||
+
|
||||
+ switch_node = of_find_node_by_name(NULL, "ess-switch");
|
||||
+ if (!switch_node) {
|
||||
+ pr_err("switch-node not found\n");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ ess_rst = of_reset_control_get(switch_node, "ess_rst");
|
||||
+ of_node_put(switch_node);
|
||||
+
|
||||
+ if (IS_ERR(ess_rst)) {
|
||||
+ pr_err("failed to find ess_rst!\n");
|
||||
+ return -ENOENT;
|
||||
+ }
|
||||
+
|
||||
+ reset_control_assert(ess_rst);
|
||||
+ msleep(10);
|
||||
+ reset_control_deassert(ess_rst);
|
||||
+ msleep(100);
|
||||
+ reset_control_put(ess_rst);
|
||||
+
|
||||
+ /* Enable only port 5 <--> port 0
|
||||
+ * bits 0:6 bitmap of ports it can fwd to */
|
||||
+#define SET_PORT_BMP(r,v) \
|
||||
+ ess_read_reg(edma, r, ®val); \
|
||||
+ ess_write_reg(edma, r, ((regval & ~0x3F) | v));
|
||||
+
|
||||
+ SET_PORT_BMP(ESS_PORT0_LOOKUP_CTRL,0x20);
|
||||
+ SET_PORT_BMP(ESS_PORT1_LOOKUP_CTRL,0x00);
|
||||
+ SET_PORT_BMP(ESS_PORT2_LOOKUP_CTRL,0x00);
|
||||
+ SET_PORT_BMP(ESS_PORT3_LOOKUP_CTRL,0x00);
|
||||
+ SET_PORT_BMP(ESS_PORT4_LOOKUP_CTRL,0x00);
|
||||
+ SET_PORT_BMP(ESS_PORT5_LOOKUP_CTRL,0x01);
|
||||
+ ess_write_reg(edma, ESS_RGMII_CTRL, 0x400);
|
||||
+ ess_write_reg(edma, ESS_PORT0_STATUS, ESS_PORT_1G_FDX);
|
||||
+ ess_write_reg(edma, ESS_PORT5_STATUS, ESS_PORT_1G_FDX);
|
||||
+ ess_write_reg(edma, ESS_PORT0_HEADER_CTRL, 0);
|
||||
+#undef SET_PORT_BMP
|
||||
+
|
||||
+ /* forward multicast and broadcast frames to CPU */
|
||||
+ ess_write_reg(edma, ESS_FWD_CTRL1,
|
||||
+ (ESS_PORTS_ALL << ESS_FWD_CTRL1_UC_FLOOD_S) |
|
||||
+ (ESS_PORTS_ALL << ESS_FWD_CTRL1_MC_FLOOD_S) |
|
||||
+ (ESS_PORTS_ALL << ESS_FWD_CTRL1_BC_FLOOD_S));
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+void ess_set_port_status_speed(struct edma_common_info *edma,
|
||||
+ struct phy_device *phydev, uint8_t port_id)
|
||||
+{
|
||||
+ uint16_t reg_off = ESS_PORT0_STATUS + (4 * port_id);
|
||||
+ uint32_t reg_val = 0;
|
||||
+
|
||||
+ ess_read_reg(edma, reg_off, ®_val);
|
||||
+
|
||||
+ /* reset the speed bits [0:1] */
|
||||
+ reg_val &= ~ESS_PORT_STATUS_SPEED_INV;
|
||||
+
|
||||
+ /* set the new speed */
|
||||
+ switch(phydev->speed) {
|
||||
+ case SPEED_1000: reg_val |= ESS_PORT_STATUS_SPEED_1000; break;
|
||||
+ case SPEED_100: reg_val |= ESS_PORT_STATUS_SPEED_100; break;
|
||||
+ case SPEED_10: reg_val |= ESS_PORT_STATUS_SPEED_10; break;
|
||||
+ default: reg_val |= ESS_PORT_STATUS_SPEED_INV; break;
|
||||
+ }
|
||||
+
|
||||
+ /* check full/half duplex */
|
||||
+ if (phydev->duplex) {
|
||||
+ reg_val |= ESS_PORT_STATUS_DUPLEX_MODE;
|
||||
+ } else {
|
||||
+ reg_val &= ~ESS_PORT_STATUS_DUPLEX_MODE;
|
||||
+ }
|
||||
+
|
||||
+ ess_write_reg(edma, reg_off, reg_val);
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * edma_change_tx_coalesce()
|
||||
* change tx interrupt moderation timer
|
||||
*/
|
||||
void edma_change_tx_coalesce(int usecs)
|
||||
@@ -551,6 +652,31 @@ static struct ctl_table edma_table[] = {
|
||||
{}
|
||||
};
|
||||
|
||||
+static int ess_parse(struct edma_common_info *edma)
|
||||
+{
|
||||
+ struct device_node *switch_node;
|
||||
+ int ret = -EINVAL;
|
||||
+
|
||||
+ switch_node = of_find_node_by_name(NULL, "ess-switch");
|
||||
+ if (!switch_node) {
|
||||
+ pr_err("cannot find ess-switch node\n");
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ edma->ess_hw_addr = of_io_request_and_map(switch_node,
|
||||
+ 0, KBUILD_MODNAME);
|
||||
+ if (!edma->ess_hw_addr) {
|
||||
+ pr_err("%s ioremap fail.", __func__);
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ edma->ess_clk = of_clk_get_by_name(switch_node, "ess_clk");
|
||||
+ ret = clk_prepare_enable(edma->ess_clk);
|
||||
+out:
|
||||
+ of_node_put(switch_node);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
/* edma_axi_netdev_ops
|
||||
* Describe the operations supported by registered netdevices
|
||||
*
|
||||
@@ -786,6 +912,17 @@ static int edma_axi_probe(struct platfor
|
||||
miibus = mdio_data->mii_bus;
|
||||
}
|
||||
|
||||
+ if (of_property_read_bool(np, "qcom,single-phy") &&
|
||||
+ edma_cinfo->num_gmac == 1) {
|
||||
+ err = ess_parse(edma_cinfo);
|
||||
+ if (!err)
|
||||
+ err = ess_reset(edma_cinfo);
|
||||
+ if (err)
|
||||
+ goto err_single_phy_init;
|
||||
+ else
|
||||
+ edma_cinfo->is_single_phy = true;
|
||||
+ }
|
||||
+
|
||||
for_each_available_child_of_node(np, pnp) {
|
||||
const char *mac_addr;
|
||||
|
||||
@@ -1074,11 +1211,15 @@ static int edma_axi_probe(struct platfor
|
||||
|
||||
for (i = 0; i < edma_cinfo->num_gmac; i++) {
|
||||
if (adapter[i]->poll_required) {
|
||||
+ int phy_mode = of_get_phy_mode(np);
|
||||
+
|
||||
+ if (phy_mode < 0)
|
||||
+ phy_mode = PHY_INTERFACE_MODE_SGMII;
|
||||
adapter[i]->phydev =
|
||||
phy_connect(edma_netdev[i],
|
||||
(const char *)adapter[i]->phy_id,
|
||||
&edma_adjust_link,
|
||||
- PHY_INTERFACE_MODE_SGMII);
|
||||
+ phy_mode);
|
||||
if (IS_ERR(adapter[i]->phydev)) {
|
||||
dev_dbg(&pdev->dev, "PHY attach FAIL");
|
||||
err = -EIO;
|
||||
@@ -1125,6 +1266,9 @@ err_rmap_alloc_fail:
|
||||
for (i = 0; i < edma_cinfo->num_gmac; i++)
|
||||
unregister_netdev(edma_netdev[i]);
|
||||
err_register:
|
||||
+err_single_phy_init:
|
||||
+ iounmap(edma_cinfo->ess_hw_addr);
|
||||
+ clk_disable_unprepare(edma_cinfo->ess_clk);
|
||||
err_mdiobus_init_fail:
|
||||
edma_free_rx_rings(edma_cinfo);
|
||||
err_rx_rinit:
|
||||
@@ -1185,6 +1329,8 @@ static int edma_axi_remove(struct platfo
|
||||
del_timer_sync(&edma_stats_timer);
|
||||
edma_free_irqs(adapter);
|
||||
unregister_net_sysctl_table(edma_cinfo->edma_ctl_table_hdr);
|
||||
+ iounmap(edma_cinfo->ess_hw_addr);
|
||||
+ clk_disable_unprepare(edma_cinfo->ess_clk);
|
||||
edma_free_tx_resources(edma_cinfo);
|
||||
edma_free_rx_resources(edma_cinfo);
|
||||
edma_free_tx_rings(edma_cinfo);
|
||||
--- a/drivers/net/ethernet/qualcomm/essedma/edma.c
|
||||
+++ b/drivers/net/ethernet/qualcomm/essedma/edma.c
|
||||
@@ -161,8 +161,10 @@ static void edma_configure_rx(struct edm
|
||||
/* Set Rx FIFO threshold to start to DMA data to host */
|
||||
rxq_ctrl_data = EDMA_FIFO_THRESH_128_BYTE;
|
||||
|
||||
- /* Set RX remove vlan bit */
|
||||
- rxq_ctrl_data |= EDMA_RXQ_CTRL_RMV_VLAN;
|
||||
+ if (!edma_cinfo->is_single_phy) {
|
||||
+ /* Set RX remove vlan bit */
|
||||
+ rxq_ctrl_data |= EDMA_RXQ_CTRL_RMV_VLAN;
|
||||
+ }
|
||||
|
||||
edma_write_reg(EDMA_REG_RXQ_CTRL, rxq_ctrl_data);
|
||||
}
|
||||
@@ -1295,6 +1297,10 @@ void edma_adjust_link(struct net_device
|
||||
if (status == __EDMA_LINKUP && adapter->link_state == __EDMA_LINKDOWN) {
|
||||
dev_info(&adapter->pdev->dev, "%s: GMAC Link is up with phy_speed=%d\n", netdev->name, phydev->speed);
|
||||
adapter->link_state = __EDMA_LINKUP;
|
||||
+ if (adapter->edma_cinfo->is_single_phy) {
|
||||
+ ess_set_port_status_speed(adapter->edma_cinfo, phydev,
|
||||
+ ffs(adapter->dp_bitmap) - 1);
|
||||
+ }
|
||||
netif_carrier_on(netdev);
|
||||
if (netif_running(netdev))
|
||||
netif_tx_wake_all_queues(netdev);
|
||||
@@ -1388,10 +1394,12 @@ netdev_tx_t edma_xmit(struct sk_buff *sk
|
||||
}
|
||||
|
||||
/* Check and mark VLAN tag offload */
|
||||
- if (skb_vlan_tag_present(skb))
|
||||
- flags_transmit |= EDMA_VLAN_TX_TAG_INSERT_FLAG;
|
||||
- else if (adapter->default_vlan_tag)
|
||||
- flags_transmit |= EDMA_VLAN_TX_TAG_INSERT_DEFAULT_FLAG;
|
||||
+ if (!adapter->edma_cinfo->is_single_phy) {
|
||||
+ if (unlikely(skb_vlan_tag_present(skb)))
|
||||
+ flags_transmit |= EDMA_VLAN_TX_TAG_INSERT_FLAG;
|
||||
+ else if (adapter->default_vlan_tag)
|
||||
+ flags_transmit |= EDMA_VLAN_TX_TAG_INSERT_DEFAULT_FLAG;
|
||||
+ }
|
||||
|
||||
/* Check and mark checksum offload */
|
||||
if (likely(skb->ip_summed == CHECKSUM_PARTIAL))
|
||||
--- a/drivers/net/ethernet/qualcomm/essedma/edma.h
|
||||
+++ b/drivers/net/ethernet/qualcomm/essedma/edma.h
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
+#include <linux/clk.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/sysctl.h>
|
||||
@@ -331,6 +332,10 @@ struct edma_common_info {
|
||||
struct edma_hw hw; /* edma hw specific structure */
|
||||
struct edma_per_cpu_queues_info edma_percpu_info[CONFIG_NR_CPUS]; /* per cpu information */
|
||||
spinlock_t stats_lock; /* protect edma stats area for updation */
|
||||
+
|
||||
+ bool is_single_phy;
|
||||
+ void __iomem *ess_hw_addr;
|
||||
+ struct clk *ess_clk;
|
||||
};
|
||||
|
||||
/* transimit packet descriptor (tpd) ring */
|
||||
@@ -443,4 +448,6 @@ void edma_change_tx_coalesce(int usecs);
|
||||
void edma_change_rx_coalesce(int usecs);
|
||||
void edma_get_tx_rx_coalesce(u32 *reg_val);
|
||||
void edma_clear_irq_status(void);
|
||||
+void ess_set_port_status_speed(struct edma_common_info *edma_cinfo,
|
||||
+ struct phy_device *phydev, uint8_t port_id);
|
||||
#endif /* _EDMA_H_ */
|
||||
--- a/drivers/net/ethernet/qualcomm/essedma/ess_edma.h
|
||||
+++ b/drivers/net/ethernet/qualcomm/essedma/ess_edma.h
|
||||
@@ -329,4 +329,61 @@ struct edma_hw;
|
||||
#define EDMA_RRD_PRIORITY_MASK 0x7
|
||||
#define EDMA_RRD_PORT_TYPE_SHIFT 7
|
||||
#define EDMA_RRD_PORT_TYPE_MASK 0x1F
|
||||
+
|
||||
+#define ESS_RGMII_CTRL 0x0004
|
||||
+
|
||||
+/* Port status registers */
|
||||
+#define ESS_PORT0_STATUS 0x007C
|
||||
+#define ESS_PORT1_STATUS 0x0080
|
||||
+#define ESS_PORT2_STATUS 0x0084
|
||||
+#define ESS_PORT3_STATUS 0x0088
|
||||
+#define ESS_PORT4_STATUS 0x008C
|
||||
+#define ESS_PORT5_STATUS 0x0090
|
||||
+
|
||||
+#define ESS_PORT_STATUS_HDX_FLOW_CTL 0x80
|
||||
+#define ESS_PORT_STATUS_DUPLEX_MODE 0x40
|
||||
+#define ESS_PORT_STATUS_RX_FLOW_EN 0x20
|
||||
+#define ESS_PORT_STATUS_TX_FLOW_EN 0x10
|
||||
+#define ESS_PORT_STATUS_RX_MAC_EN 0x08
|
||||
+#define ESS_PORT_STATUS_TX_MAC_EN 0x04
|
||||
+#define ESS_PORT_STATUS_SPEED_INV 0x03
|
||||
+#define ESS_PORT_STATUS_SPEED_1000 0x02
|
||||
+#define ESS_PORT_STATUS_SPEED_100 0x01
|
||||
+#define ESS_PORT_STATUS_SPEED_10 0x00
|
||||
+
|
||||
+#define ESS_PORT_1G_FDX (ESS_PORT_STATUS_DUPLEX_MODE | ESS_PORT_STATUS_RX_FLOW_EN | \
|
||||
+ ESS_PORT_STATUS_TX_FLOW_EN | ESS_PORT_STATUS_RX_MAC_EN | \
|
||||
+ ESS_PORT_STATUS_TX_MAC_EN | ESS_PORT_STATUS_SPEED_1000)
|
||||
+
|
||||
+#define PHY_STATUS_REG 0x11
|
||||
+#define PHY_STATUS_SPEED 0xC000
|
||||
+#define PHY_STATUS_SPEED_SHIFT 14
|
||||
+#define PHY_STATUS_DUPLEX 0x2000
|
||||
+#define PHY_STATUS_DUPLEX_SHIFT 13
|
||||
+#define PHY_STATUS_SPEED_DUPLEX_RESOLVED 0x0800
|
||||
+#define PHY_STATUS_CARRIER 0x0400
|
||||
+#define PHY_STATUS_CARRIER_SHIFT 10
|
||||
+
|
||||
+/* Port lookup control registers */
|
||||
+#define ESS_PORT0_LOOKUP_CTRL 0x0660
|
||||
+#define ESS_PORT1_LOOKUP_CTRL 0x066C
|
||||
+#define ESS_PORT2_LOOKUP_CTRL 0x0678
|
||||
+#define ESS_PORT3_LOOKUP_CTRL 0x0684
|
||||
+#define ESS_PORT4_LOOKUP_CTRL 0x0690
|
||||
+#define ESS_PORT5_LOOKUP_CTRL 0x069C
|
||||
+
|
||||
+#define ESS_PORT0_HEADER_CTRL 0x009C
|
||||
+
|
||||
+#define ESS_PORTS_ALL 0x3f
|
||||
+
|
||||
+#define ESS_FWD_CTRL1 0x0624
|
||||
+#define ESS_FWD_CTRL1_UC_FLOOD BITS(0, 7)
|
||||
+#define ESS_FWD_CTRL1_UC_FLOOD_S 0
|
||||
+#define ESS_FWD_CTRL1_MC_FLOOD BITS(8, 7)
|
||||
+#define ESS_FWD_CTRL1_MC_FLOOD_S 8
|
||||
+#define ESS_FWD_CTRL1_BC_FLOOD BITS(16, 7)
|
||||
+#define ESS_FWD_CTRL1_BC_FLOOD_S 16
|
||||
+#define ESS_FWD_CTRL1_IGMP BITS(24, 7)
|
||||
+#define ESS_FWD_CTRL1_IGMP_S 24
|
||||
+
|
||||
#endif /* _ESS_EDMA_H_ */
|
||||
@ -1,21 +0,0 @@
|
||||
From 17681f0bb474d0d227f07369144149d1555d8bce Mon Sep 17 00:00:00 2001
|
||||
From: Chen Minqiang <ptpt52@gmail.com>
|
||||
Date: Sun, 17 Jun 2018 04:14:13 +0800
|
||||
Subject: [PATCH] essedma: alloc skb ip align
|
||||
|
||||
Signed-off-by: Chen Minqiang <ptpt52@gmail.com>
|
||||
---
|
||||
drivers/net/ethernet/qualcomm/essedma/edma.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/net/ethernet/qualcomm/essedma/edma.c
|
||||
+++ b/drivers/net/ethernet/qualcomm/essedma/edma.c
|
||||
@@ -201,7 +201,7 @@ static int edma_alloc_rx_buf(struct edma
|
||||
skb = sw_desc->skb;
|
||||
} else {
|
||||
/* alloc skb */
|
||||
- skb = netdev_alloc_skb(edma_netdev[0], length);
|
||||
+ skb = netdev_alloc_skb_ip_align(edma_netdev[0], length);
|
||||
if (!skb) {
|
||||
/* Better luck next round */
|
||||
break;
|
||||
@ -1,197 +0,0 @@
|
||||
From 72c050acbc425ef99313d5c2e4c866e25567e569 Mon Sep 17 00:00:00 2001
|
||||
From: Rakesh Nair <ranair@codeaurora.org>
|
||||
Date: Thu, 8 Jun 2017 14:29:20 +0530
|
||||
Subject: [PATCH] CHROMIUM: net: qualcomm: Add fix for memory allocation issues
|
||||
|
||||
Added ethtool counters for memory allocation failures accounting.
|
||||
Added support to track number of allocation failures that could
|
||||
not be fulfilled in the current iteration in the rx descriptor
|
||||
field and use the info to allocate in the subsequent iteration.
|
||||
|
||||
Change-Id: Ie4fd3b6cf25304e5db2c9247a498791e7e9bb4aa
|
||||
Signed-off-by: Rakesh Nair <ranair@codeaurora.org>
|
||||
Signed-off-by: Kan Yan <kyan@google.com>
|
||||
Reviewed-on: https://chromium-review.googlesource.com/535419
|
||||
Reviewed-by: Grant Grundler <grundler@chromium.org>
|
||||
---
|
||||
drivers/net/ethernet/qualcomm/essedma/edma.c | 54 ++++++++++++++-----
|
||||
drivers/net/ethernet/qualcomm/essedma/edma.h | 2 +
|
||||
.../ethernet/qualcomm/essedma/edma_ethtool.c | 1 +
|
||||
3 files changed, 43 insertions(+), 14 deletions(-)
|
||||
|
||||
--- a/drivers/net/ethernet/qualcomm/essedma/edma.c
|
||||
+++ b/drivers/net/ethernet/qualcomm/essedma/edma.c
|
||||
@@ -103,6 +103,9 @@ static int edma_alloc_rx_ring(struct edm
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
+ /* Initialize pending_fill */
|
||||
+ erxd->pending_fill = 0;
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -185,11 +188,8 @@ static int edma_alloc_rx_buf(struct edma
|
||||
u16 prod_idx, length;
|
||||
u32 reg_data;
|
||||
|
||||
- if (cleaned_count > erdr->count) {
|
||||
- dev_err(&pdev->dev, "Incorrect cleaned_count %d",
|
||||
- cleaned_count);
|
||||
- return -1;
|
||||
- }
|
||||
+ if (cleaned_count > erdr->count)
|
||||
+ cleaned_count = erdr->count - 1;
|
||||
|
||||
i = erdr->sw_next_to_fill;
|
||||
|
||||
@@ -199,6 +199,9 @@ static int edma_alloc_rx_buf(struct edma
|
||||
|
||||
if (sw_desc->flags & EDMA_SW_DESC_FLAG_SKB_REUSE) {
|
||||
skb = sw_desc->skb;
|
||||
+
|
||||
+ /* Clear REUSE Flag */
|
||||
+ sw_desc->flags &= ~EDMA_SW_DESC_FLAG_SKB_REUSE;
|
||||
} else {
|
||||
/* alloc skb */
|
||||
skb = netdev_alloc_skb_ip_align(edma_netdev[0], length);
|
||||
@@ -264,6 +267,13 @@ static int edma_alloc_rx_buf(struct edma
|
||||
reg_data &= ~EDMA_RFD_PROD_IDX_BITS;
|
||||
reg_data |= prod_idx;
|
||||
edma_write_reg(EDMA_REG_RFD_IDX_Q(queue_id), reg_data);
|
||||
+
|
||||
+ /* If we couldn't allocate all the buffers
|
||||
+ * we increment the alloc failure counters
|
||||
+ */
|
||||
+ if (cleaned_count)
|
||||
+ edma_cinfo->edma_ethstats.rx_alloc_fail_ctr++;
|
||||
+
|
||||
return cleaned_count;
|
||||
}
|
||||
|
||||
@@ -534,7 +544,7 @@ static int edma_rx_complete_paged(struct
|
||||
* edma_rx_complete()
|
||||
* Main api called from the poll function to process rx packets.
|
||||
*/
|
||||
-static void edma_rx_complete(struct edma_common_info *edma_cinfo,
|
||||
+static u16 edma_rx_complete(struct edma_common_info *edma_cinfo,
|
||||
int *work_done, int work_to_do, int queue_id,
|
||||
struct napi_struct *napi)
|
||||
{
|
||||
@@ -554,6 +564,7 @@ static void edma_rx_complete(struct edma
|
||||
u16 count = erdr->count, rfd_avail;
|
||||
u8 queue_to_rxid[8] = {0, 0, 1, 1, 2, 2, 3, 3};
|
||||
|
||||
+ cleaned_count = erdr->pending_fill;
|
||||
sw_next_to_clean = erdr->sw_next_to_clean;
|
||||
|
||||
edma_read_reg(EDMA_REG_RFD_IDX_Q(queue_id), &data);
|
||||
@@ -652,12 +663,13 @@ static void edma_rx_complete(struct edma
|
||||
(*work_done)++;
|
||||
drop_count = 0;
|
||||
}
|
||||
- if (cleaned_count == EDMA_RX_BUFFER_WRITE) {
|
||||
+ if (cleaned_count >= EDMA_RX_BUFFER_WRITE) {
|
||||
/* If buffer clean count reaches 16, we replenish HW buffers. */
|
||||
ret_count = edma_alloc_rx_buf(edma_cinfo, erdr, cleaned_count, queue_id);
|
||||
edma_write_reg(EDMA_REG_RX_SW_CONS_IDX_Q(queue_id),
|
||||
sw_next_to_clean);
|
||||
cleaned_count = ret_count;
|
||||
+ erdr->pending_fill = ret_count;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -730,11 +742,12 @@ static void edma_rx_complete(struct edma
|
||||
adapter->stats.rx_bytes += length;
|
||||
|
||||
/* Check if we reached refill threshold */
|
||||
- if (cleaned_count == EDMA_RX_BUFFER_WRITE) {
|
||||
+ if (cleaned_count >= EDMA_RX_BUFFER_WRITE) {
|
||||
ret_count = edma_alloc_rx_buf(edma_cinfo, erdr, cleaned_count, queue_id);
|
||||
edma_write_reg(EDMA_REG_RX_SW_CONS_IDX_Q(queue_id),
|
||||
sw_next_to_clean);
|
||||
cleaned_count = ret_count;
|
||||
+ erdr->pending_fill = ret_count;
|
||||
}
|
||||
|
||||
/* At this point skb should go to stack */
|
||||
@@ -756,11 +769,17 @@ static void edma_rx_complete(struct edma
|
||||
/* Refill here in case refill threshold wasn't reached */
|
||||
if (likely(cleaned_count)) {
|
||||
ret_count = edma_alloc_rx_buf(edma_cinfo, erdr, cleaned_count, queue_id);
|
||||
- if (ret_count)
|
||||
- dev_dbg(&pdev->dev, "Not all buffers was reallocated");
|
||||
+ erdr->pending_fill = ret_count;
|
||||
+ if (ret_count) {
|
||||
+ if (net_ratelimit())
|
||||
+ dev_dbg(&pdev->dev, "Not all buffers was reallocated");
|
||||
+ }
|
||||
+
|
||||
edma_write_reg(EDMA_REG_RX_SW_CONS_IDX_Q(queue_id),
|
||||
erdr->sw_next_to_clean);
|
||||
}
|
||||
+
|
||||
+ return erdr->pending_fill;
|
||||
}
|
||||
|
||||
/* edma_delete_rfs_filter()
|
||||
@@ -2064,6 +2083,7 @@ int edma_poll(struct napi_struct *napi,
|
||||
u32 shadow_rx_status, shadow_tx_status;
|
||||
int queue_id;
|
||||
int i, work_done = 0;
|
||||
+ u16 rx_pending_fill;
|
||||
|
||||
/* Store the Rx/Tx status by ANDing it with
|
||||
* appropriate CPU RX?TX mask
|
||||
@@ -2097,13 +2117,19 @@ int edma_poll(struct napi_struct *napi,
|
||||
*/
|
||||
while (edma_percpu_info->rx_status) {
|
||||
queue_id = ffs(edma_percpu_info->rx_status) - 1;
|
||||
- edma_rx_complete(edma_cinfo, &work_done,
|
||||
- budget, queue_id, napi);
|
||||
+ rx_pending_fill = edma_rx_complete(edma_cinfo, &work_done,
|
||||
+ budget, queue_id, napi);
|
||||
|
||||
- if (likely(work_done < budget))
|
||||
+ if (likely(work_done < budget)) {
|
||||
+ if (rx_pending_fill) {
|
||||
+ /* reschedule poll() to refill rx buffer deficit */
|
||||
+ work_done = budget;
|
||||
+ break;
|
||||
+ }
|
||||
edma_percpu_info->rx_status &= ~(1 << queue_id);
|
||||
- else
|
||||
+ } else {
|
||||
break;
|
||||
+ }
|
||||
}
|
||||
|
||||
/* Clear the status register, to avoid the interrupts to
|
||||
--- a/drivers/net/ethernet/qualcomm/essedma/edma.h
|
||||
+++ b/drivers/net/ethernet/qualcomm/essedma/edma.h
|
||||
@@ -225,6 +225,7 @@ struct edma_ethtool_statistics {
|
||||
u32 rx_q6_byte;
|
||||
u32 rx_q7_byte;
|
||||
u32 tx_desc_error;
|
||||
+ u32 rx_alloc_fail_ctr;
|
||||
};
|
||||
|
||||
struct edma_mdio_data {
|
||||
@@ -362,6 +363,7 @@ struct edma_rfd_desc_ring {
|
||||
dma_addr_t dma; /* descriptor ring physical address */
|
||||
u16 sw_next_to_fill; /* next descriptor to fill */
|
||||
u16 sw_next_to_clean; /* next descriptor to clean */
|
||||
+ u16 pending_fill; /* fill pending from previous iteration */
|
||||
};
|
||||
|
||||
/* edma_rfs_flter_node - rfs filter node in hash table */
|
||||
--- a/drivers/net/ethernet/qualcomm/essedma/edma_ethtool.c
|
||||
+++ b/drivers/net/ethernet/qualcomm/essedma/edma_ethtool.c
|
||||
@@ -78,6 +78,7 @@ static const struct edma_ethtool_stats e
|
||||
{"rx_q6_byte", EDMA_STAT(rx_q6_byte)},
|
||||
{"rx_q7_byte", EDMA_STAT(rx_q7_byte)},
|
||||
{"tx_desc_error", EDMA_STAT(tx_desc_error)},
|
||||
+ {"rx_alloc_fail_ctr", EDMA_STAT(rx_alloc_fail_ctr)},
|
||||
};
|
||||
|
||||
#define EDMA_STATS_LEN ARRAY_SIZE(edma_gstrings_stats)
|
||||
@ -1,199 +0,0 @@
|
||||
--- a/drivers/net/ethernet/qualcomm/essedma/edma.c
|
||||
+++ b/drivers/net/ethernet/qualcomm/essedma/edma.c
|
||||
@@ -22,14 +22,6 @@ extern struct net_device *edma_netdev[ED
|
||||
bool edma_stp_rstp;
|
||||
u16 edma_ath_eth_type;
|
||||
|
||||
-/* edma_skb_priority_offset()
|
||||
- * get edma skb priority
|
||||
- */
|
||||
-static unsigned int edma_skb_priority_offset(struct sk_buff *skb)
|
||||
-{
|
||||
- return (skb->priority >> 2) & 1;
|
||||
-}
|
||||
-
|
||||
/* edma_alloc_tx_ring()
|
||||
* Allocate Tx descriptors ring
|
||||
*/
|
||||
@@ -1018,13 +1010,14 @@ static inline u16 edma_tpd_available(str
|
||||
/* edma_tx_queue_get()
|
||||
* Get the starting number of the queue
|
||||
*/
|
||||
-static inline int edma_tx_queue_get(struct edma_adapter *adapter,
|
||||
+static inline int edma_tx_queue_get(struct edma_common_info *edma_cinfo, struct edma_adapter *adapter,
|
||||
struct sk_buff *skb, int txq_id)
|
||||
{
|
||||
/* skb->priority is used as an index to skb priority table
|
||||
* and based on packet priority, correspong queue is assigned.
|
||||
+ * FIXME we just simple use jiffies for time base balance
|
||||
*/
|
||||
- return adapter->tx_start_offset[txq_id] + edma_skb_priority_offset(skb);
|
||||
+ return adapter->tx_start_offset[txq_id] + (smp_processor_id() % edma_cinfo->num_txq_per_core_netdev);
|
||||
}
|
||||
|
||||
/* edma_tx_update_hw_idx()
|
||||
@@ -1393,8 +1386,9 @@ netdev_tx_t edma_xmit(struct sk_buff *sk
|
||||
}
|
||||
|
||||
/* this will be one of the 4 TX queues exposed to linux kernel */
|
||||
- txq_id = skb_get_queue_mapping(skb);
|
||||
- queue_id = edma_tx_queue_get(adapter, skb, txq_id);
|
||||
+ /* XXX what if num_online_cpus() > EDMA_CPU_CORES_SUPPORTED */
|
||||
+ txq_id = ((jiffies >> 5) % (EDMA_CPU_CORES_SUPPORTED - 1) + smp_processor_id() + 1) % EDMA_CPU_CORES_SUPPORTED;
|
||||
+ queue_id = edma_tx_queue_get(edma_cinfo, adapter, skb, txq_id);
|
||||
etdr = edma_cinfo->tpd_ring[queue_id];
|
||||
nq = netdev_get_tx_queue(net_dev, txq_id);
|
||||
|
||||
@@ -1875,8 +1869,8 @@ void edma_free_irqs(struct edma_adapter
|
||||
int i, j;
|
||||
int k = ((edma_cinfo->num_rx_queues == 4) ? 1 : 2);
|
||||
|
||||
- for (i = 0; i < CONFIG_NR_CPUS; i++) {
|
||||
- for (j = edma_cinfo->edma_percpu_info[i].tx_start; j < (edma_cinfo->edma_percpu_info[i].tx_start + 4); j++)
|
||||
+ for (i = 0; i < num_online_cpus() && i < EDMA_CPU_CORES_SUPPORTED; i++) {
|
||||
+ for (j = edma_cinfo->edma_percpu_info[i].tx_start; j < (edma_cinfo->edma_percpu_info[i].tx_start + edma_cinfo->num_txq_per_core); j++)
|
||||
free_irq(edma_cinfo->tx_irq[j], &edma_cinfo->edma_percpu_info[i]);
|
||||
|
||||
for (j = edma_cinfo->edma_percpu_info[i].rx_start; j < (edma_cinfo->edma_percpu_info[i].rx_start + k); j++)
|
||||
--- a/drivers/net/ethernet/qualcomm/essedma/edma.h
|
||||
+++ b/drivers/net/ethernet/qualcomm/essedma/edma.h
|
||||
@@ -324,6 +324,7 @@ struct edma_common_info {
|
||||
u32 from_cpu; /* from CPU TPD field */
|
||||
u32 num_rxq_per_core; /* Rx queues per core */
|
||||
u32 num_txq_per_core; /* Tx queues per core */
|
||||
+ u32 num_txq_per_core_netdev; /* Tx queues per core per netdev */
|
||||
u16 tx_ring_count; /* Tx ring count */
|
||||
u16 rx_ring_count; /* Rx ring*/
|
||||
u16 rx_head_buffer_len; /* rx buffer length */
|
||||
@@ -331,7 +332,7 @@ struct edma_common_info {
|
||||
u32 page_mode; /* Jumbo frame supported flag */
|
||||
u32 fraglist_mode; /* fraglist supported flag */
|
||||
struct edma_hw hw; /* edma hw specific structure */
|
||||
- struct edma_per_cpu_queues_info edma_percpu_info[CONFIG_NR_CPUS]; /* per cpu information */
|
||||
+ struct edma_per_cpu_queues_info edma_percpu_info[EDMA_CPU_CORES_SUPPORTED]; /* per cpu information */
|
||||
spinlock_t stats_lock; /* protect edma stats area for updation */
|
||||
|
||||
bool is_single_phy;
|
||||
@@ -401,7 +402,7 @@ struct edma_adapter {
|
||||
u32 link_state; /* phy link state */
|
||||
u32 phy_mdio_addr; /* PHY device address on MII interface */
|
||||
u32 poll_required; /* check if link polling is required */
|
||||
- u32 tx_start_offset[CONFIG_NR_CPUS]; /* tx queue start */
|
||||
+ u32 tx_start_offset[EDMA_CPU_CORES_SUPPORTED]; /* tx queue start */
|
||||
u32 default_vlan_tag; /* vlan tag */
|
||||
u32 dp_bitmap;
|
||||
uint8_t phy_id[MII_BUS_ID_SIZE + 3];
|
||||
--- a/drivers/net/ethernet/qualcomm/essedma/edma_axi.c
|
||||
+++ b/drivers/net/ethernet/qualcomm/essedma/edma_axi.c
|
||||
@@ -721,11 +721,7 @@ static int edma_axi_probe(struct platfor
|
||||
int i, j, k, err = 0;
|
||||
int portid_bmp;
|
||||
int idx = 0, idx_mac = 0;
|
||||
-
|
||||
- if (CONFIG_NR_CPUS != EDMA_CPU_CORES_SUPPORTED) {
|
||||
- dev_err(&pdev->dev, "Invalid CPU Cores\n");
|
||||
- return -EINVAL;
|
||||
- }
|
||||
+ int netdev_group = 2;
|
||||
|
||||
if ((num_rxq != 4) && (num_rxq != 8)) {
|
||||
dev_err(&pdev->dev, "Invalid RX queue, edma probe failed\n");
|
||||
@@ -749,7 +745,7 @@ static int edma_axi_probe(struct platfor
|
||||
/* Initialize the netdev array before allocation
|
||||
* to avoid double free
|
||||
*/
|
||||
- for (i = 0 ; i < edma_cinfo->num_gmac ; i++)
|
||||
+ for (i = 0 ; i < EDMA_MAX_PORTID_SUPPORTED; i++)
|
||||
edma_netdev[i] = NULL;
|
||||
|
||||
for (i = 0 ; i < edma_cinfo->num_gmac ; i++) {
|
||||
@@ -770,8 +766,11 @@ static int edma_axi_probe(struct platfor
|
||||
|
||||
/* Fill ring details */
|
||||
edma_cinfo->num_tx_queues = EDMA_MAX_TRANSMIT_QUEUE;
|
||||
- edma_cinfo->num_txq_per_core = (EDMA_MAX_TRANSMIT_QUEUE / 4);
|
||||
+ edma_cinfo->num_txq_per_core = (EDMA_MAX_TRANSMIT_QUEUE / num_online_cpus());
|
||||
+ edma_cinfo->num_txq_per_core_netdev = (EDMA_MAX_TRANSMIT_QUEUE / netdev_group / num_online_cpus());
|
||||
edma_cinfo->tx_ring_count = EDMA_TX_RING_SIZE;
|
||||
+ if (edma_cinfo->num_txq_per_core == 0)
|
||||
+ edma_cinfo->num_txq_per_core = 1;
|
||||
|
||||
/* Update num rx queues based on module parameter */
|
||||
edma_cinfo->num_rx_queues = num_rxq;
|
||||
@@ -941,6 +940,13 @@ static int edma_axi_probe(struct platfor
|
||||
idx_mac++;
|
||||
}
|
||||
|
||||
+ if (edma_cinfo->num_gmac == 1) {
|
||||
+ netdev_group = 1;
|
||||
+ edma_cinfo->num_txq_per_core_netdev = (EDMA_MAX_TRANSMIT_QUEUE / netdev_group / num_online_cpus());
|
||||
+ }
|
||||
+ if (edma_cinfo->num_txq_per_core_netdev == 0)
|
||||
+ edma_cinfo->num_txq_per_core_netdev = 1;
|
||||
+
|
||||
/* Populate the adapter structure register the netdevice */
|
||||
for (i = 0; i < edma_cinfo->num_gmac; i++) {
|
||||
int k, m;
|
||||
@@ -948,17 +954,16 @@ static int edma_axi_probe(struct platfor
|
||||
adapter[i] = netdev_priv(edma_netdev[i]);
|
||||
adapter[i]->netdev = edma_netdev[i];
|
||||
adapter[i]->pdev = pdev;
|
||||
- for (j = 0; j < CONFIG_NR_CPUS; j++) {
|
||||
- m = i % 2;
|
||||
- adapter[i]->tx_start_offset[j] =
|
||||
- ((j << EDMA_TX_CPU_START_SHIFT) + (m << 1));
|
||||
+ for (j = 0; j < num_online_cpus() && j < EDMA_CPU_CORES_SUPPORTED; j++) {
|
||||
+ m = i % netdev_group;
|
||||
+ adapter[i]->tx_start_offset[j] = j * edma_cinfo->num_txq_per_core + m * edma_cinfo->num_txq_per_core_netdev;
|
||||
/* Share the queues with available net-devices.
|
||||
* For instance , with 5 net-devices
|
||||
* eth0/eth2/eth4 will share q0,q1,q4,q5,q8,q9,q12,q13
|
||||
* and eth1/eth3 will get the remaining.
|
||||
*/
|
||||
for (k = adapter[i]->tx_start_offset[j]; k <
|
||||
- (adapter[i]->tx_start_offset[j] + 2); k++) {
|
||||
+ (adapter[i]->tx_start_offset[j] + edma_cinfo->num_txq_per_core_netdev); k++) {
|
||||
if (edma_fill_netdev(edma_cinfo, k, i, j)) {
|
||||
pr_err("Netdev overflow Error\n");
|
||||
goto err_register;
|
||||
@@ -1111,9 +1116,12 @@ static int edma_axi_probe(struct platfor
|
||||
/* populate per_core_info, do a napi_Add, request 16 TX irqs,
|
||||
* 8 RX irqs, do a napi enable
|
||||
*/
|
||||
- for (i = 0; i < CONFIG_NR_CPUS; i++) {
|
||||
+ for (i = 0; i < num_online_cpus() && i < EDMA_CPU_CORES_SUPPORTED; i++) {
|
||||
u8 rx_start;
|
||||
|
||||
+ tx_mask[i] = (0xFFFF >> (16 - edma_cinfo->num_txq_per_core)) << (i * edma_cinfo->num_txq_per_core);
|
||||
+ tx_start[i] = i * edma_cinfo->num_txq_per_core;
|
||||
+
|
||||
edma_cinfo->edma_percpu_info[i].napi.state = 0;
|
||||
|
||||
netif_napi_add(edma_netdev[0],
|
||||
@@ -1133,7 +1141,7 @@ static int edma_axi_probe(struct platfor
|
||||
|
||||
/* Request irq per core */
|
||||
for (j = edma_cinfo->edma_percpu_info[i].tx_start;
|
||||
- j < tx_start[i] + 4; j++) {
|
||||
+ j < tx_start[i] + edma_cinfo->num_txq_per_core; j++) {
|
||||
sprintf(&edma_tx_irq[j][0], "edma_eth_tx%d", j);
|
||||
err = request_irq(edma_cinfo->tx_irq[j],
|
||||
edma_interrupt,
|
||||
@@ -1258,7 +1266,7 @@ err_configure:
|
||||
#endif
|
||||
err_rmap_add_fail:
|
||||
edma_free_irqs(adapter[0]);
|
||||
- for (i = 0; i < CONFIG_NR_CPUS; i++)
|
||||
+ for (i = 0; i < num_online_cpus() && i < EDMA_CPU_CORES_SUPPORTED; i++)
|
||||
napi_disable(&edma_cinfo->edma_percpu_info[i].napi);
|
||||
err_reset:
|
||||
err_unregister_sysctl_tbl:
|
||||
@@ -1306,7 +1314,7 @@ static int edma_axi_remove(struct platfo
|
||||
unregister_netdev(edma_netdev[i]);
|
||||
|
||||
edma_stop_rx_tx(hw);
|
||||
- for (i = 0; i < CONFIG_NR_CPUS; i++)
|
||||
+ for (i = 0; i < num_online_cpus() && i < EDMA_CPU_CORES_SUPPORTED; i++)
|
||||
napi_disable(&edma_cinfo->edma_percpu_info[i].napi);
|
||||
|
||||
edma_irq_disable(edma_cinfo);
|
||||
@ -1,52 +0,0 @@
|
||||
--- a/drivers/net/ethernet/qualcomm/essedma/edma.c
|
||||
+++ b/drivers/net/ethernet/qualcomm/essedma/edma.c
|
||||
@@ -2079,15 +2079,13 @@ int edma_poll(struct napi_struct *napi,
|
||||
int i, work_done = 0;
|
||||
u16 rx_pending_fill;
|
||||
|
||||
- /* Store the Rx/Tx status by ANDing it with
|
||||
- * appropriate CPU RX?TX mask
|
||||
+ /* Store the Tx status by ANDing it with
|
||||
+ * appropriate CPU TX mask
|
||||
*/
|
||||
- edma_read_reg(EDMA_REG_RX_ISR, ®_data);
|
||||
- edma_percpu_info->rx_status |= reg_data & edma_percpu_info->rx_mask;
|
||||
- shadow_rx_status = edma_percpu_info->rx_status;
|
||||
edma_read_reg(EDMA_REG_TX_ISR, ®_data);
|
||||
edma_percpu_info->tx_status |= reg_data & edma_percpu_info->tx_mask;
|
||||
shadow_tx_status = edma_percpu_info->tx_status;
|
||||
+ edma_write_reg(EDMA_REG_TX_ISR, shadow_tx_status);
|
||||
|
||||
/* Every core will have a start, which will be computed
|
||||
* in probe and stored in edma_percpu_info->tx_start variable.
|
||||
@@ -2102,6 +2100,14 @@ int edma_poll(struct napi_struct *napi,
|
||||
edma_percpu_info->tx_status &= ~(1 << queue_id);
|
||||
}
|
||||
|
||||
+ /* Store the Rx status by ANDing it with
|
||||
+ * appropriate CPU RX mask
|
||||
+ */
|
||||
+ edma_read_reg(EDMA_REG_RX_ISR, ®_data);
|
||||
+ edma_percpu_info->rx_status |= reg_data & edma_percpu_info->rx_mask;
|
||||
+ shadow_rx_status = edma_percpu_info->rx_status;
|
||||
+ edma_write_reg(EDMA_REG_RX_ISR, shadow_rx_status);
|
||||
+
|
||||
/* Every core will have a start, which will be computed
|
||||
* in probe and stored in edma_percpu_info->tx_start variable.
|
||||
* We will shift the status bit by tx_start to obtain
|
||||
@@ -2126,15 +2132,6 @@ int edma_poll(struct napi_struct *napi,
|
||||
}
|
||||
}
|
||||
|
||||
- /* Clear the status register, to avoid the interrupts to
|
||||
- * reoccur.This clearing of interrupt status register is
|
||||
- * done here as writing to status register only takes place
|
||||
- * once the producer/consumer index has been updated to
|
||||
- * reflect that the packet transmission/reception went fine.
|
||||
- */
|
||||
- edma_write_reg(EDMA_REG_RX_ISR, shadow_rx_status);
|
||||
- edma_write_reg(EDMA_REG_TX_ISR, shadow_tx_status);
|
||||
-
|
||||
/* If budget not fully consumed, exit the polling mode */
|
||||
if (likely(work_done < budget)) {
|
||||
napi_complete(napi);
|
||||
@ -1,46 +0,0 @@
|
||||
From: Sven Eckelmann <sven@narfation.org>
|
||||
Date: Tue, 9 Jun 2020 14:08:44 +0200
|
||||
Subject: essedma: Disable TCP segmentation offload for IPv6
|
||||
|
||||
It was noticed that the the whole MAC can hang when transferring data from
|
||||
one ar40xx port (WAN ports) to the CPU and from the CPU back to another
|
||||
ar40xx port (LAN ports). The CPU was doing only NATing in that process.
|
||||
|
||||
Usually, the problem first starts with a simple data corruption:
|
||||
|
||||
$ wget https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/debian-10.4.0-amd64-netinst.iso -O /dev/null
|
||||
...
|
||||
Connecting to saimei.ftp.acc.umu.se (saimei.ftp.acc.umu.se)|2001:6b0:19::138|:443... connected.
|
||||
...
|
||||
Read error at byte 48807936/352321536 (Decryption has failed.). Retrying.
|
||||
|
||||
But after a short while, the whole MAC will stop to react. No traffic can
|
||||
be transported anymore from the CPU port from/to the AR40xx PHY/switch and
|
||||
the MAC has to be resetted.
|
||||
|
||||
Signed-off-by: Sven Eckelmann <sven@narfation.org>
|
||||
|
||||
--- a/drivers/net/ethernet/qualcomm/essedma/edma_axi.c
|
||||
+++ b/drivers/net/ethernet/qualcomm/essedma/edma_axi.c
|
||||
@@ -977,17 +977,14 @@ static int edma_axi_probe(struct platfor
|
||||
edma_netdev[i]->features = NETIF_F_HW_CSUM | NETIF_F_RXCSUM
|
||||
| NETIF_F_HW_VLAN_CTAG_TX
|
||||
| NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_SG |
|
||||
- NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_GRO;
|
||||
+ NETIF_F_TSO | NETIF_F_GRO;
|
||||
edma_netdev[i]->hw_features = NETIF_F_HW_CSUM | NETIF_F_RXCSUM |
|
||||
NETIF_F_HW_VLAN_CTAG_RX
|
||||
- | NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 |
|
||||
- NETIF_F_GRO;
|
||||
+ | NETIF_F_SG | NETIF_F_TSO | NETIF_F_GRO;
|
||||
edma_netdev[i]->vlan_features = NETIF_F_HW_CSUM | NETIF_F_SG |
|
||||
- NETIF_F_TSO | NETIF_F_TSO6 |
|
||||
- NETIF_F_GRO;
|
||||
+ NETIF_F_TSO | NETIF_F_GRO;
|
||||
edma_netdev[i]->wanted_features = NETIF_F_HW_CSUM | NETIF_F_SG |
|
||||
- NETIF_F_TSO | NETIF_F_TSO6 |
|
||||
- NETIF_F_GRO;
|
||||
+ NETIF_F_TSO | NETIF_F_GRO;
|
||||
|
||||
#ifdef CONFIG_RFS_ACCEL
|
||||
edma_netdev[i]->features |= NETIF_F_RXHASH | NETIF_F_NTUPLE;
|
||||
@ -1,177 +0,0 @@
|
||||
From: Christian Lamparter <chunkeey@googlemail.com>
|
||||
Subject: SoC: add qualcomm syscon
|
||||
--- a/drivers/soc/qcom/Makefile
|
||||
+++ b/drivers/soc/qcom/Makefile
|
||||
@@ -9,3 +9,4 @@ obj-$(CONFIG_QCOM_SMEM_STATE) += smem_st
|
||||
obj-$(CONFIG_QCOM_SMP2P) += smp2p.o
|
||||
obj-$(CONFIG_QCOM_SMSM) += smsm.o
|
||||
obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o
|
||||
+obj-$(CONFIG_QCOM_TCSR) += qcom_tcsr.o
|
||||
--- a/drivers/soc/qcom/Kconfig
|
||||
+++ b/drivers/soc/qcom/Kconfig
|
||||
@@ -78,6 +78,13 @@ config QCOM_SMSM
|
||||
Say yes here to support the Qualcomm Shared Memory State Machine.
|
||||
The state machine is represented by bits in shared memory.
|
||||
|
||||
+config QCOM_TCSR
|
||||
+ tristate "QCOM Top Control and Status Registers"
|
||||
+ depends on ARCH_QCOM
|
||||
+ help
|
||||
+ Say y here to enable TCSR support. The TCSR provides control
|
||||
+ functions for various peripherals.
|
||||
+
|
||||
config QCOM_WCNSS_CTRL
|
||||
tristate "Qualcomm WCNSS control driver"
|
||||
depends on ARCH_QCOM
|
||||
--- /dev/null
|
||||
+++ b/drivers/soc/qcom/qcom_tcsr.c
|
||||
@@ -0,0 +1,98 @@
|
||||
+/*
|
||||
+ * Copyright (c) 2014, The Linux foundation. All rights reserved.
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify
|
||||
+ * it under the terms of the GNU General Public License rev 2 and
|
||||
+ * only rev 2 as published by the free Software foundation.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful,
|
||||
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or fITNESS fOR A PARTICULAR PURPOSE. See the
|
||||
+ * GNU General Public License for more details.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/clk.h>
|
||||
+#include <linux/err.h>
|
||||
+#include <linux/io.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/of_platform.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+
|
||||
+#define TCSR_USB_PORT_SEL 0xb0
|
||||
+#define TCSR_USB_HSPHY_CONFIG 0xC
|
||||
+
|
||||
+#define TCSR_ESS_INTERFACE_SEL_OFFSET 0x0
|
||||
+#define TCSR_ESS_INTERFACE_SEL_MASK 0xf
|
||||
+
|
||||
+#define TCSR_WIFI0_GLB_CFG_OFFSET 0x0
|
||||
+#define TCSR_WIFI1_GLB_CFG_OFFSET 0x4
|
||||
+#define TCSR_PNOC_SNOC_MEMTYPE_M0_M2 0x4
|
||||
+
|
||||
+static int tcsr_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct resource *res;
|
||||
+ const struct device_node *node = pdev->dev.of_node;
|
||||
+ void __iomem *base;
|
||||
+ u32 val;
|
||||
+
|
||||
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
+ base = devm_ioremap_resource(&pdev->dev, res);
|
||||
+ if (IS_ERR(base))
|
||||
+ return PTR_ERR(base);
|
||||
+
|
||||
+ if (!of_property_read_u32(node, "qcom,usb-ctrl-select", &val)) {
|
||||
+ dev_err(&pdev->dev, "setting usb port select = %d\n", val);
|
||||
+ writel(val, base + TCSR_USB_PORT_SEL);
|
||||
+ }
|
||||
+
|
||||
+ if (!of_property_read_u32(node, "qcom,usb-hsphy-mode-select", &val)) {
|
||||
+ dev_info(&pdev->dev, "setting usb hs phy mode select = %x\n", val);
|
||||
+ writel(val, base + TCSR_USB_HSPHY_CONFIG);
|
||||
+ }
|
||||
+
|
||||
+ if (!of_property_read_u32(node, "qcom,ess-interface-select", &val)) {
|
||||
+ u32 tmp = 0;
|
||||
+ dev_info(&pdev->dev, "setting ess interface select = %x\n", val);
|
||||
+ tmp = readl(base + TCSR_ESS_INTERFACE_SEL_OFFSET);
|
||||
+ tmp = tmp & (~TCSR_ESS_INTERFACE_SEL_MASK);
|
||||
+ tmp = tmp | (val&TCSR_ESS_INTERFACE_SEL_MASK);
|
||||
+ writel(tmp, base + TCSR_ESS_INTERFACE_SEL_OFFSET);
|
||||
+ }
|
||||
+
|
||||
+ if (!of_property_read_u32(node, "qcom,wifi_glb_cfg", &val)) {
|
||||
+ dev_info(&pdev->dev, "setting wifi_glb_cfg = %x\n", val);
|
||||
+ writel(val, base + TCSR_WIFI0_GLB_CFG_OFFSET);
|
||||
+ writel(val, base + TCSR_WIFI1_GLB_CFG_OFFSET);
|
||||
+ }
|
||||
+
|
||||
+ if (!of_property_read_u32(node, "qcom,wifi_noc_memtype_m0_m2", &val)) {
|
||||
+ dev_info(&pdev->dev,
|
||||
+ "setting wifi_noc_memtype_m0_m2 = %x\n", val);
|
||||
+ writel(val, base + TCSR_PNOC_SNOC_MEMTYPE_M0_M2);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id tcsr_dt_match[] = {
|
||||
+ { .compatible = "qcom,tcsr", },
|
||||
+ { },
|
||||
+};
|
||||
+
|
||||
+MODULE_DEVICE_TABLE(of, tcsr_dt_match);
|
||||
+
|
||||
+static struct platform_driver tcsr_driver = {
|
||||
+ .driver = {
|
||||
+ .name = "tcsr",
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .of_match_table = tcsr_dt_match,
|
||||
+ },
|
||||
+ .probe = tcsr_probe,
|
||||
+};
|
||||
+
|
||||
+module_platform_driver(tcsr_driver);
|
||||
+
|
||||
+MODULE_AUTHOR("Andy Gross <agross@codeaurora.org>");
|
||||
+MODULE_DESCRIPTION("QCOM TCSR driver");
|
||||
+MODULE_LICENSE("GPL v2");
|
||||
--- /dev/null
|
||||
+++ b/include/dt-bindings/soc/qcom,tcsr.h
|
||||
@@ -0,0 +1,48 @@
|
||||
+/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify
|
||||
+ * it under the terms of the GNU General Public License version 2 and
|
||||
+ * only version 2 as published by the Free Software Foundation.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful,
|
||||
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
+ * GNU General Public License for more details.
|
||||
+ */
|
||||
+#ifndef __DT_BINDINGS_QCOM_TCSR_H
|
||||
+#define __DT_BINDINGS_QCOM_TCSR_H
|
||||
+
|
||||
+#define TCSR_USB_SELECT_USB3_P0 0x1
|
||||
+#define TCSR_USB_SELECT_USB3_P1 0x2
|
||||
+#define TCSR_USB_SELECT_USB3_DUAL 0x3
|
||||
+
|
||||
+/* IPQ40xx HS PHY Mode Select */
|
||||
+#define TCSR_USB_HSPHY_HOST_MODE 0x00E700E7
|
||||
+#define TCSR_USB_HSPHY_DEVICE_MODE 0x00C700E7
|
||||
+
|
||||
+/* IPQ40xx ess interface mode select */
|
||||
+#define TCSR_ESS_PSGMII 0
|
||||
+#define TCSR_ESS_PSGMII_RGMII5 1
|
||||
+#define TCSR_ESS_PSGMII_RMII0 2
|
||||
+#define TCSR_ESS_PSGMII_RMII1 4
|
||||
+#define TCSR_ESS_PSGMII_RMII0_RMII1 6
|
||||
+#define TCSR_ESS_PSGMII_RGMII4 9
|
||||
+
|
||||
+/*
|
||||
+ * IPQ40xx WiFi Global Config
|
||||
+ * Bit 30:AXID_EN
|
||||
+ * Enable AXI master bus Axid translating to confirm all txn submitted by order
|
||||
+ * Bit 24: Use locally generated socslv_wxi_bvalid
|
||||
+ * 1: use locally generate socslv_wxi_bvalid for performance.
|
||||
+ * 0: use SNOC socslv_wxi_bvalid.
|
||||
+ */
|
||||
+#define TCSR_WIFI_GLB_CFG 0x41000000
|
||||
+
|
||||
+/* IPQ40xx MEM_TYPE_SEL_M0_M2 Select Bit 26:24 - 2 NORMAL */
|
||||
+#define TCSR_WIFI_NOC_MEMTYPE_M0_M2 0x02222222
|
||||
+
|
||||
+/* TCSR A/B REG */
|
||||
+#define IPQ806X_TCSR_REG_A_ADM_CRCI_MUX_SEL 0
|
||||
+#define IPQ806X_TCSR_REG_B_ADM_CRCI_MUX_SEL 1
|
||||
+
|
||||
+#endif
|
||||
@ -1,26 +0,0 @@
|
||||
--- a/drivers/regulator/Kconfig
|
||||
+++ b/drivers/regulator/Kconfig
|
||||
@@ -314,6 +314,13 @@ config REGULATOR_HI655X
|
||||
This driver provides support for the voltage regulators of the
|
||||
Hisilicon Hi655x PMIC device.
|
||||
|
||||
+config REGULATOR_VQMMC_IPQ4019
|
||||
+ tristate "IPQ4019 VQMMC SD LDO regulator support"
|
||||
+ depends on ARCH_QCOM
|
||||
+ help
|
||||
+ This driver provides support for the VQMMC LDO I/0
|
||||
+ voltage regulator of the IPQ4019 SD/EMMC controller.
|
||||
+
|
||||
config REGULATOR_ISL9305
|
||||
tristate "Intersil ISL9305 regulator"
|
||||
depends on I2C
|
||||
--- a/drivers/regulator/Makefile
|
||||
+++ b/drivers/regulator/Makefile
|
||||
@@ -41,6 +41,7 @@ obj-$(CONFIG_REGULATOR_GPIO) += gpio-reg
|
||||
obj-$(CONFIG_REGULATOR_HI6421) += hi6421-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_HI6421V530) += hi6421v530-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_HI655X) += hi655x-regulator.o
|
||||
+obj-$(CONFIG_REGULATOR_VQMMC_IPQ4019) += ipq4019-vqmmc-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_ISL9305) += isl9305.o
|
||||
obj-$(CONFIG_REGULATOR_LM363X) += lm363x-regulator.o
|
||||
@ -1,33 +0,0 @@
|
||||
From beae4078c07d3cdc90473a2b35eb0d2b4f3c922c Mon Sep 17 00:00:00 2001
|
||||
From: Robert Marko <robimarko@gmail.com>
|
||||
Date: Sat, 14 Sep 2019 23:13:17 +0200
|
||||
Subject: [PATCH] ARM: dts: qcom: ipq4019: Add SDHCI VQMMC LDO regulator node
|
||||
|
||||
IPQ4019 has a built in SD/eMMC controller which depends on
|
||||
VQMMC LDO regulator working.
|
||||
Since we have a driver for it lets add the appropriate node for it.
|
||||
|
||||
Signed-off-by: Robert Marko <robimarko@gmail.com>
|
||||
---
|
||||
arch/arm/boot/dts/qcom-ipq4019.dtsi | 10 ++++++++++
|
||||
1 file changed, 10 insertions(+)
|
||||
|
||||
--- a/arch/arm/boot/dts/qcom-ipq4019.dtsi
|
||||
+++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi
|
||||
@@ -212,6 +212,16 @@
|
||||
interrupts = <GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
|
||||
+ vqmmc: regulator@1948000 {
|
||||
+ compatible = "qcom,ipq4019-vqmmc-regulator";
|
||||
+ reg = <0x01948000 0x4>;
|
||||
+ regulator-name = "vqmmc";
|
||||
+ regulator-min-microvolt = <1500000>;
|
||||
+ regulator-max-microvolt = <3000000>;
|
||||
+ regulator-always-on;
|
||||
+ status = "disabled";
|
||||
+ };
|
||||
+
|
||||
blsp_dma: dma@7884000 {
|
||||
compatible = "qcom,bam-v1.7.0";
|
||||
reg = <0x07884000 0x23000>;
|
||||
@ -1,41 +0,0 @@
|
||||
Subject: [PATCH] ARM: dts: qcom: ipq4019: Add SDHCI controller node
|
||||
Date: Thu, 15 Aug 2019 19:28:23 +0200
|
||||
Message-Id: <20190815172823.12028-1-robimarko@gmail.com>
|
||||
X-Mailer: git-send-email 2.21.0
|
||||
MIME-Version: 1.0
|
||||
Sender: linux-arm-msm-owner@vger.kernel.org
|
||||
Precedence: bulk
|
||||
List-ID: <linux-arm-msm.vger.kernel.org>
|
||||
X-Mailing-List: linux-arm-msm@vger.kernel.org
|
||||
X-Virus-Scanned: ClamAV using ClamSMTP
|
||||
|
||||
IPQ4019 has a built in SD/eMMC controller which is supported by the
|
||||
SDHCI MSM driver, by the "qcom,sdhci-msm-v4" binding.
|
||||
So lets add the appropriate node for it.
|
||||
|
||||
Signed-off-by: Robert Marko <robimarko@gmail.com>
|
||||
---
|
||||
arch/arm/boot/dts/qcom-ipq4019.dtsi | 12 ++++++++++++
|
||||
1 file changed, 12 insertions(+)
|
||||
|
||||
--- a/arch/arm/boot/dts/qcom-ipq4019.dtsi
|
||||
+++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi
|
||||
@@ -222,6 +222,18 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
+ sdhci: sdhci@7824900 {
|
||||
+ compatible = "qcom,sdhci-msm-v4";
|
||||
+ reg = <0x7824900 0x11c>, <0x7824000 0x800>;
|
||||
+ interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>;
|
||||
+ interrupt-names = "hc_irq", "pwr_irq";
|
||||
+ bus-width = <8>;
|
||||
+ clocks = <&gcc GCC_SDCC1_APPS_CLK>, <&gcc GCC_SDCC1_AHB_CLK>,
|
||||
+ <&gcc GCC_DCD_XO_CLK>;
|
||||
+ clock-names = "core", "iface", "xo";
|
||||
+ status = "disabled";
|
||||
+ };
|
||||
+
|
||||
blsp_dma: dma@7884000 {
|
||||
compatible = "qcom,bam-v1.7.0";
|
||||
reg = <0x07884000 0x23000>;
|
||||
@ -1,55 +0,0 @@
|
||||
From: Georgi Djakov <georgi.djakov@linaro.org>
|
||||
Date: Mon, 28 Nov 2016 19:39:20 +0200
|
||||
Subject: [PATCH v2] mmc: sdhci-msm: Add sdhci_reset() implementation
|
||||
|
||||
Signed-off-by: Georgi Djakov <georgi.djakov@linaro.org>
|
||||
---
|
||||
|
||||
drivers/mmc/host/sdhci-msm.c | 29 ++++++++++++++++++++++++++++-
|
||||
1 file changed, 28 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/mmc/host/sdhci-msm.c
|
||||
+++ b/drivers/mmc/host/sdhci-msm.c
|
||||
@@ -1139,6 +1139,33 @@ out:
|
||||
__sdhci_msm_set_clock(host, clock);
|
||||
}
|
||||
|
||||
+void sdhci_msm_reset(struct sdhci_host *host, u8 mask)
|
||||
+{
|
||||
+ unsigned long timeout = 100;
|
||||
+
|
||||
+ sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET);
|
||||
+
|
||||
+ if (mask & SDHCI_RESET_ALL) {
|
||||
+ host->clock = 0;
|
||||
+
|
||||
+ /*
|
||||
+ * SDHCI_RESET_ALL triggers the PWR IRQ
|
||||
+ * and we need to handle it here.
|
||||
+ */
|
||||
+ sdhci_msm_voltage_switch(host);
|
||||
+ }
|
||||
+
|
||||
+ while (sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask) {
|
||||
+ if (timeout == 0) {
|
||||
+ pr_err("%s: Reset 0x%x never completed.\n",
|
||||
+ mmc_hostname(host->mmc), (int)mask);
|
||||
+ return;
|
||||
+ }
|
||||
+ timeout--;
|
||||
+ mdelay(1);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static void sdhci_msm_write_w(struct sdhci_host *host, u16 val, int reg)
|
||||
{
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
@@ -1170,7 +1197,7 @@ static const struct of_device_id sdhci_m
|
||||
MODULE_DEVICE_TABLE(of, sdhci_msm_dt_match);
|
||||
|
||||
static const struct sdhci_ops sdhci_msm_ops = {
|
||||
- .reset = sdhci_reset,
|
||||
+ .reset = sdhci_msm_reset,
|
||||
.set_clock = sdhci_set_clock,
|
||||
.get_min_clock = sdhci_msm_get_min_clock,
|
||||
.get_max_clock = sdhci_msm_get_max_clock,
|
||||
@ -1,157 +0,0 @@
|
||||
--- a/arch/arm/boot/dts/qcom-ipq4019-ap.dk01.1.dtsi
|
||||
+++ b/arch/arm/boot/dts/qcom-ipq4019-ap.dk01.1.dtsi
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
#include "qcom-ipq4019.dtsi"
|
||||
+#include <dt-bindings/soc/qcom,tcsr.h>
|
||||
|
||||
/ {
|
||||
model = "Qualcomm Technologies, Inc. IPQ4019/AP-DK01.1";
|
||||
@@ -29,6 +30,32 @@
|
||||
};
|
||||
|
||||
soc {
|
||||
+ tcsr@194b000 {
|
||||
+ /* select hostmode */
|
||||
+ compatible = "qcom,tcsr";
|
||||
+ reg = <0x194b000 0x100>;
|
||||
+ qcom,usb-hsphy-mode-select = <TCSR_USB_HSPHY_HOST_MODE>;
|
||||
+ status = "ok";
|
||||
+ };
|
||||
+
|
||||
+ ess_tcsr@1953000 {
|
||||
+ compatible = "qcom,tcsr";
|
||||
+ reg = <0x1953000 0x1000>;
|
||||
+ qcom,ess-interface-select = <TCSR_ESS_PSGMII>;
|
||||
+ };
|
||||
+
|
||||
+ tcsr@1949000 {
|
||||
+ compatible = "qcom,tcsr";
|
||||
+ reg = <0x1949000 0x100>;
|
||||
+ qcom,wifi_glb_cfg = <TCSR_WIFI_GLB_CFG>;
|
||||
+ };
|
||||
+
|
||||
+ tcsr@1957000 {
|
||||
+ compatible = "qcom,tcsr";
|
||||
+ reg = <0x1957000 0x100>;
|
||||
+ qcom,wifi_noc_memtype_m0_m2 = <TCSR_WIFI_NOC_MEMTYPE_M0_M2>;
|
||||
+ };
|
||||
+
|
||||
rng@22000 {
|
||||
status = "ok";
|
||||
};
|
||||
@@ -74,14 +101,6 @@
|
||||
pinctrl-names = "default";
|
||||
status = "ok";
|
||||
cs-gpios = <&tlmm 54 0>;
|
||||
-
|
||||
- mx25l25635e@0 {
|
||||
- #address-cells = <1>;
|
||||
- #size-cells = <1>;
|
||||
- reg = <0>;
|
||||
- compatible = "mx25l25635e";
|
||||
- spi-max-frequency = <24000000>;
|
||||
- };
|
||||
};
|
||||
|
||||
serial@78af000 {
|
||||
@@ -110,6 +129,22 @@
|
||||
status = "ok";
|
||||
};
|
||||
|
||||
+ mdio@90000 {
|
||||
+ status = "okay";
|
||||
+ };
|
||||
+
|
||||
+ ess-switch@c000000 {
|
||||
+ status = "okay";
|
||||
+ };
|
||||
+
|
||||
+ ess-psgmii@98000 {
|
||||
+ status = "okay";
|
||||
+ };
|
||||
+
|
||||
+ edma@c080000 {
|
||||
+ status = "okay";
|
||||
+ };
|
||||
+
|
||||
usb3_ss_phy: ssphy@9a000 {
|
||||
status = "ok";
|
||||
};
|
||||
--- a/arch/arm/boot/dts/qcom-ipq4019-ap.dk01.1-c1.dts
|
||||
+++ b/arch/arm/boot/dts/qcom-ipq4019-ap.dk01.1-c1.dts
|
||||
@@ -18,5 +18,73 @@
|
||||
|
||||
/ {
|
||||
model = "Qualcomm Technologies, Inc. IPQ40xx/AP-DK01.1-C1";
|
||||
+ compatible = "qcom,ap-dk01.1-c1", "qcom,ap-dk01.2-c1", "qcom,ipq4019";
|
||||
|
||||
+ memory {
|
||||
+ device_type = "memory";
|
||||
+ reg = <0x80000000 0x10000000>;
|
||||
+ };
|
||||
+};
|
||||
+
|
||||
+&blsp1_spi1 {
|
||||
+ mx25l25635f@0 {
|
||||
+ compatible = "mx25l25635f", "jedec,spi-nor";
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <1>;
|
||||
+ reg = <0>;
|
||||
+ spi-max-frequency = <24000000>;
|
||||
+
|
||||
+ SBL1@0 {
|
||||
+ label = "SBL1";
|
||||
+ reg = <0x0 0x40000>;
|
||||
+ read-only;
|
||||
+ };
|
||||
+ MIBIB@40000 {
|
||||
+ label = "MIBIB";
|
||||
+ reg = <0x40000 0x20000>;
|
||||
+ read-only;
|
||||
+ };
|
||||
+ QSEE@60000 {
|
||||
+ label = "QSEE";
|
||||
+ reg = <0x60000 0x60000>;
|
||||
+ read-only;
|
||||
+ };
|
||||
+ CDT@c0000 {
|
||||
+ label = "CDT";
|
||||
+ reg = <0xc0000 0x10000>;
|
||||
+ read-only;
|
||||
+ };
|
||||
+ DDRPARAMS@d0000 {
|
||||
+ label = "DDRPARAMS";
|
||||
+ reg = <0xd0000 0x10000>;
|
||||
+ read-only;
|
||||
+ };
|
||||
+ APPSBLENV@e0000 {
|
||||
+ label = "APPSBLENV";
|
||||
+ reg = <0xe0000 0x10000>;
|
||||
+ read-only;
|
||||
+ };
|
||||
+ APPSBL@f0000 {
|
||||
+ label = "APPSBL";
|
||||
+ reg = <0xf0000 0x80000>;
|
||||
+ read-only;
|
||||
+ };
|
||||
+ ART@170000 {
|
||||
+ label = "ART";
|
||||
+ reg = <0x170000 0x10000>;
|
||||
+ read-only;
|
||||
+ };
|
||||
+ kernel@180000 {
|
||||
+ label = "kernel";
|
||||
+ reg = <0x180000 0x400000>;
|
||||
+ };
|
||||
+ rootfs@580000 {
|
||||
+ label = "rootfs";
|
||||
+ reg = <0x580000 0x1600000>;
|
||||
+ };
|
||||
+ firmware@180000 {
|
||||
+ label = "firmware";
|
||||
+ reg = <0x180000 0x1a00000>;
|
||||
+ };
|
||||
+ };
|
||||
};
|
||||
@ -1,67 +0,0 @@
|
||||
From 8f68331e14dff9a101f2d0e1d6bec84a031f27ee Mon Sep 17 00:00:00 2001
|
||||
From: John Crispin <john@phrozen.org>
|
||||
Date: Thu, 9 Mar 2017 11:03:18 +0100
|
||||
Subject: [PATCH 69/69] arm: boot: add dts files
|
||||
|
||||
Signed-off-by: John Crispin <john@phrozen.org>
|
||||
---
|
||||
arch/arm/boot/dts/Makefile | 8 ++++++++
|
||||
1 file changed, 8 insertions(+)
|
||||
|
||||
--- a/arch/arm/boot/dts/Makefile
|
||||
+++ b/arch/arm/boot/dts/Makefile
|
||||
@@ -697,7 +697,54 @@ dtb-$(CONFIG_ARCH_QCOM) += \
|
||||
qcom-apq8074-dragonboard.dtb \
|
||||
qcom-apq8084-ifc6540.dtb \
|
||||
qcom-apq8084-mtp.dtb \
|
||||
+ qcom-ipq4018-a42.dtb \
|
||||
+ qcom-ipq4018-ap120c-ac.dtb \
|
||||
+ qcom-ipq4018-dap-2610.dtb \
|
||||
+ qcom-ipq4018-cs-w3-wd1200g-eup.dtb \
|
||||
+ qcom-ipq4018-ea6350v3.dtb \
|
||||
+ qcom-ipq4018-eap1300.dtb \
|
||||
+ qcom-ipq4018-emd1.dtb \
|
||||
+ qcom-ipq4018-emr3500.dtb \
|
||||
+ qcom-ipq4018-ens620ext.dtb \
|
||||
+ qcom-ipq4018-ex6100v2.dtb \
|
||||
+ qcom-ipq4018-ex6150v2.dtb \
|
||||
+ qcom-ipq4018-ex6200v2.dtb \
|
||||
+ qcom-ipq4018-fritzbox-4040.dtb \
|
||||
+ qcom-ipq4018-jalapeno.dtb \
|
||||
+ qcom-ipq4018-meshpoint-one.dtb \
|
||||
+ qcom-ipq4018-nbg6617.dtb \
|
||||
+ qcom-ipq4018-rt-ac58u.dtb \
|
||||
+ qcom-ipq4018-wre6606.dtb \
|
||||
qcom-ipq4019-ap.dk01.1-c1.dtb \
|
||||
+ qcom-ipq4019-ap.dk04.1-c1.dtb \
|
||||
+ qcom-ipq4019-a62.dtb \
|
||||
+ qcom-ipq4019-c526a.dtb \
|
||||
+ qcom-ipq4019-cm520-79f.dtb \
|
||||
+ qcom-ipq4019-ea8300.dtb \
|
||||
+ qcom-ipq4019-eap2200.dtb \
|
||||
+ qcom-ipq4019-hugo-ac1200.dtb \
|
||||
+ qcom-ipq4019-fritzbox-7530.dtb \
|
||||
+ qcom-ipq4019-fritzrepeater-1200.dtb \
|
||||
+ qcom-ipq4019-fritzrepeater-3000.dtb \
|
||||
+ qcom-ipq4019-map-ac2200.dtb \
|
||||
+ qcom-ipq4019-e2600ac-c1.dtb \
|
||||
+ qcom-ipq4019-e2600ac-c2.dtb \
|
||||
+ qcom-ipq4019-habanero-dvk.dtb \
|
||||
+ qcom-ipq4019-r619ac.dtb \
|
||||
+ qcom-ipq4019-rtl30vw.dtb \
|
||||
+ qcom-ipq4019-rt-acrh17.dtb \
|
||||
+ qcom-ipq4019-u4019-32m.dtb \
|
||||
+ qcom-ipq4019-wpj419.dtb \
|
||||
+ qcom-ipq4019-wr142ac.dtb \
|
||||
+ qcom-ipq4019-wr142ac-nand.dtb \
|
||||
+ qcom-ipq4019-wtr-m2133hp.dtb \
|
||||
+ qcom-ipq4028-wpj428.dtb \
|
||||
+ qcom-ipq4029-ap-303.dtb \
|
||||
+ qcom-ipq4029-ap-303h.dtb \
|
||||
+ qcom-ipq4029-ap-365.dtb \
|
||||
+ qcom-ipq4029-gl-b1300.dtb \
|
||||
+ qcom-ipq4029-gl-s1300.dtb \
|
||||
+ qcom-ipq4029-mr33.dtb \
|
||||
qcom-ipq8064-ap148.dtb \
|
||||
qcom-msm8660-surf.dtb \
|
||||
qcom-msm8960-cdp.dtb \
|
||||
@ -1,75 +0,0 @@
|
||||
From 42b508d91b7f51b054f383e3aa42089ccab9300d Mon Sep 17 00:00:00 2001
|
||||
From: Chen Minqiang <ptpt52@gmail.com>
|
||||
Date: Thu, 15 Mar 2018 05:33:46 +0800
|
||||
Subject: [PATCH] essedma: disable default vlan tagging
|
||||
|
||||
The essedma driver has its own unique take on VLAN management
|
||||
and its configuration. In the original SDK, each VLAN is
|
||||
assigned one virtual ethernet netdev.
|
||||
|
||||
However, this is non-standard. So, this patch does away
|
||||
with the default_vlan_tag property the driver is using
|
||||
and therefore forces the user to use the kernel's vlan
|
||||
feature.
|
||||
|
||||
This patch also removes the "qcom,poll_required = <1>;" from
|
||||
the essedma node.
|
||||
|
||||
Signed-off-by: Christian Lamparter <chunkeey@googlemail.com>
|
||||
Signed-off-by: Chen Minqiang <ptpt52@gmail.com>
|
||||
---
|
||||
arch/arm/boot/dts/qcom-ipq4019.dtsi | 5 ++---
|
||||
drivers/net/ethernet/qualcomm/essedma/edma.c | 14 +++++---------
|
||||
2 files changed, 7 insertions(+), 12 deletions(-)
|
||||
|
||||
--- a/arch/arm/boot/dts/qcom-ipq4019.dtsi
|
||||
+++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi
|
||||
@@ -648,8 +648,7 @@
|
||||
qcom,page-mode = <0>;
|
||||
qcom,rx_head_buf_size = <1540>;
|
||||
qcom,mdio_supported;
|
||||
- qcom,poll_required = <1>;
|
||||
- qcom,num_gmac = <2>;
|
||||
+ qcom,num_gmac = <1>;
|
||||
interrupts = <0 65 IRQ_TYPE_EDGE_RISING
|
||||
0 66 IRQ_TYPE_EDGE_RISING
|
||||
0 67 IRQ_TYPE_EDGE_RISING
|
||||
@@ -687,7 +686,7 @@
|
||||
|
||||
gmac0: gmac0 {
|
||||
local-mac-address = [00 00 00 00 00 00];
|
||||
- vlan_tag = <1 0x1f>;
|
||||
+ vlan_tag = <1 0x3f>;
|
||||
};
|
||||
|
||||
gmac1: gmac1 {
|
||||
--- a/drivers/net/ethernet/qualcomm/essedma/edma.c
|
||||
+++ b/drivers/net/ethernet/qualcomm/essedma/edma.c
|
||||
@@ -721,13 +721,11 @@ static u16 edma_rx_complete(struct edma_
|
||||
edma_receive_checksum(rd, skb);
|
||||
|
||||
/* Process VLAN HW acceleration indication provided by HW */
|
||||
- if (unlikely(adapter->default_vlan_tag != rd->rrd4)) {
|
||||
- vlan = rd->rrd4;
|
||||
- if (likely(rd->rrd7 & EDMA_RRD_CVLAN))
|
||||
- __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan);
|
||||
- else if (rd->rrd1 & EDMA_RRD_SVLAN)
|
||||
- __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021AD), vlan);
|
||||
- }
|
||||
+ vlan = rd->rrd4;
|
||||
+ if (likely(rd->rrd7 & EDMA_RRD_CVLAN))
|
||||
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan);
|
||||
+ else if (rd->rrd1 & EDMA_RRD_SVLAN)
|
||||
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021AD), vlan);
|
||||
|
||||
/* Update rx statistics */
|
||||
adapter->stats.rx_packets++;
|
||||
@@ -1410,8 +1408,6 @@ netdev_tx_t edma_xmit(struct sk_buff *sk
|
||||
if (!adapter->edma_cinfo->is_single_phy) {
|
||||
if (unlikely(skb_vlan_tag_present(skb)))
|
||||
flags_transmit |= EDMA_VLAN_TX_TAG_INSERT_FLAG;
|
||||
- else if (adapter->default_vlan_tag)
|
||||
- flags_transmit |= EDMA_VLAN_TX_TAG_INSERT_DEFAULT_FLAG;
|
||||
}
|
||||
|
||||
/* Check and mark checksum offload */
|
||||
@ -1,313 +0,0 @@
|
||||
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
|
||||
index 4f76ba5d78a9..eef0d931dd4e 100644
|
||||
--- a/drivers/net/wireless/ath/ath10k/core.c
|
||||
+++ b/drivers/net/wireless/ath/ath10k/core.c
|
||||
@@ -38,18 +38,21 @@
|
||||
static bool uart_print;
|
||||
static bool skip_otp;
|
||||
static bool rawmode;
|
||||
+static bool ethernetmode;
|
||||
|
||||
module_param_named(debug_mask, ath10k_debug_mask, uint, 0644);
|
||||
module_param_named(cryptmode, ath10k_cryptmode_param, uint, 0644);
|
||||
module_param(uart_print, bool, 0644);
|
||||
module_param(skip_otp, bool, 0644);
|
||||
module_param(rawmode, bool, 0644);
|
||||
+module_param(ethernetmode, bool, 0644);
|
||||
|
||||
MODULE_PARM_DESC(debug_mask, "Debugging mask");
|
||||
MODULE_PARM_DESC(uart_print, "Uart target debugging");
|
||||
MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode");
|
||||
MODULE_PARM_DESC(cryptmode, "Crypto mode: 0-hardware, 1-software");
|
||||
MODULE_PARM_DESC(rawmode, "Use raw 802.11 frame datapath");
|
||||
+MODULE_PARM_DESC(ethernetmode, "Use ethernet frame datapath");
|
||||
|
||||
static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
||||
{
|
||||
@@ -2390,6 +2393,15 @@
|
||||
|
||||
/* peer stats are enabled by default */
|
||||
set_bit(ATH10K_FLAG_PEER_STATS, &ar->dev_flags);
|
||||
+
|
||||
+ if (ethernetmode && rawmode) {
|
||||
+ ath10k_err(ar, "ethernet and raw mode cannot co-exist\n");
|
||||
+ status = -EINVAL;
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
+ ar->ethernetmode = ethernetmode;
|
||||
+
|
||||
|
||||
status = ath10k_core_probe_fw(ar);
|
||||
if (status) {
|
||||
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
|
||||
index af68eb5d0776..251fb57cbe8f 100644
|
||||
--- a/drivers/net/wireless/ath/ath10k/core.h
|
||||
+++ b/drivers/net/wireless/ath/ath10k/core.h
|
||||
@@ -117,6 +117,7 @@
|
||||
ATH10K_SKB_F_DELIVER_CAB = BIT(2),
|
||||
ATH10K_SKB_F_MGMT = BIT(3),
|
||||
ATH10K_SKB_F_QOS = BIT(4),
|
||||
+ ATH10K_SKB_F_HW_80211_ENCAP = BIT(6),
|
||||
};
|
||||
|
||||
struct ath10k_skb_cb {
|
||||
@@ -1000,6 +1001,8 @@
|
||||
u32 ampdu_reference;
|
||||
|
||||
void *ce_priv;
|
||||
+
|
||||
+ bool ethernetmode;
|
||||
|
||||
/* must be last */
|
||||
u8 drv_priv[0] __aligned(sizeof(void *));
|
||||
diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c
|
||||
index a182c0944cc7..0ca0705fe69a 100644
|
||||
--- a/drivers/net/wireless/ath/ath10k/htt_tx.c
|
||||
+++ b/drivers/net/wireless/ath/ath10k/htt_tx.c
|
||||
@@ -812,6 +812,10 @@ static u8 ath10k_htt_tx_get_tid(struct sk_buff *skb, bool is_eth)
|
||||
struct ieee80211_hdr *hdr = (void *)skb->data;
|
||||
struct ath10k_skb_cb *cb = ATH10K_SKB_CB(skb);
|
||||
|
||||
+ /* Firmware takes care of tid classification for ethernet format */
|
||||
+ if (cb->flags & ATH10K_SKB_F_HW_80211_ENCAP)
|
||||
+ return skb->priority % IEEE80211_QOS_CTL_TID_MASK;
|
||||
+
|
||||
if (!is_eth && ieee80211_is_mgmt(hdr->frame_control))
|
||||
return HTT_DATA_TX_EXT_TID_MGMT;
|
||||
else if (cb->flags & ATH10K_SKB_F_QOS)
|
||||
@@ -933,15 +937,17 @@ int ath10k_htt_tx(struct ath10k_htt *htt, enum ath10k_hw_txrx_mode txmode,
|
||||
txbuf_paddr = htt->txbuf.paddr +
|
||||
(sizeof(struct ath10k_htt_txbuf) * msdu_id);
|
||||
|
||||
- if ((ieee80211_is_action(hdr->frame_control) ||
|
||||
- ieee80211_is_deauth(hdr->frame_control) ||
|
||||
- ieee80211_is_disassoc(hdr->frame_control)) &&
|
||||
- ieee80211_has_protected(hdr->frame_control)) {
|
||||
- skb_put(msdu, IEEE80211_CCMP_MIC_LEN);
|
||||
- } else if (!(skb_cb->flags & ATH10K_SKB_F_NO_HWCRYPT) &&
|
||||
- txmode == ATH10K_HW_TXRX_RAW &&
|
||||
- ieee80211_has_protected(hdr->frame_control)) {
|
||||
- skb_put(msdu, IEEE80211_CCMP_MIC_LEN);
|
||||
+ if (!(info->control.flags & IEEE80211_TX_CTRL_HW_80211_ENCAP)) {
|
||||
+ if ((ieee80211_is_action(hdr->frame_control) ||
|
||||
+ ieee80211_is_deauth(hdr->frame_control) ||
|
||||
+ ieee80211_is_disassoc(hdr->frame_control)) &&
|
||||
+ ieee80211_has_protected(hdr->frame_control)) {
|
||||
+ skb_put(msdu, IEEE80211_CCMP_MIC_LEN);
|
||||
+ } else if (!(skb_cb->flags & ATH10K_SKB_F_NO_HWCRYPT) &&
|
||||
+ txmode == ATH10K_HW_TXRX_RAW &&
|
||||
+ ieee80211_has_protected(hdr->frame_control)) {
|
||||
+ skb_put(msdu, IEEE80211_CCMP_MIC_LEN);
|
||||
+ }
|
||||
}
|
||||
|
||||
skb_cb->paddr = dma_map_single(dev, msdu->data, msdu->len,
|
||||
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
|
||||
index 83cc8778ca1e..0ea0d0be74a1 100644
|
||||
--- a/drivers/net/wireless/ath/ath10k/mac.c
|
||||
+++ b/drivers/net/wireless/ath/ath10k/mac.c
|
||||
@@ -3363,10 +3363,14 @@
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
const struct ieee80211_hdr *hdr = (void *)skb->data;
|
||||
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
||||
__le16 fc = hdr->frame_control;
|
||||
|
||||
if (!vif || vif->type == NL80211_IFTYPE_MONITOR)
|
||||
return ATH10K_HW_TXRX_RAW;
|
||||
+
|
||||
+ if (tx_info->control.flags & IEEE80211_TX_CTRL_HW_80211_ENCAP)
|
||||
+ return ATH10K_HW_TXRX_ETHERNET;
|
||||
|
||||
if (ieee80211_is_mgmt(fc))
|
||||
return ATH10K_HW_TXRX_MGMT;
|
||||
@@ -3516,6 +3520,15 @@
|
||||
struct ath10k_skb_cb *cb = ATH10K_SKB_CB(skb);
|
||||
|
||||
cb->flags = 0;
|
||||
+ cb->vif = vif;
|
||||
+ cb->txq = txq;
|
||||
+ cb->airtime_est = airtime;
|
||||
+
|
||||
+ if (info->control.flags & IEEE80211_TX_CTRL_HW_80211_ENCAP) {
|
||||
+ cb->flags |= ATH10K_SKB_F_HW_80211_ENCAP;
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
if (!ath10k_tx_h_use_hwcrypto(vif, skb))
|
||||
cb->flags |= ATH10K_SKB_F_NO_HWCRYPT;
|
||||
|
||||
@@ -3525,8 +3538,6 @@
|
||||
if (ieee80211_is_data_qos(hdr->frame_control))
|
||||
cb->flags |= ATH10K_SKB_F_QOS;
|
||||
|
||||
- cb->vif = vif;
|
||||
- cb->txq = txq;
|
||||
}
|
||||
|
||||
bool ath10k_mac_tx_frm_has_freq(struct ath10k *ar)
|
||||
@@ -3631,7 +3642,10 @@
|
||||
{
|
||||
struct ieee80211_hw *hw = ar->hw;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
- int ret;
|
||||
+ int ret;.
|
||||
+
|
||||
+ if (info->control.flags & IEEE80211_TX_CTRL_HW_80211_ENCAP)
|
||||
+ goto skip_encap;
|
||||
|
||||
/* We should disable CCK RATE due to P2P */
|
||||
if (info->flags & IEEE80211_TX_CTL_NO_CCK_RATE)
|
||||
@@ -3655,6 +3669,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
+ skip_encap:
|
||||
if (!noque_offchan && info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) {
|
||||
if (!ath10k_mac_tx_frm_has_freq(ar)) {
|
||||
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac queued offchannel skb %pK len %d\n",
|
||||
@@ -3704,6 +3719,7 @@
|
||||
int ret;
|
||||
unsigned long time_left;
|
||||
bool tmp_peer_created = false;
|
||||
+ struct ieee80211_tx_info *info;
|
||||
|
||||
/* FW requirement: We must create a peer before FW will send out
|
||||
* an offchannel frame. Otherwise the frame will be stuck and
|
||||
@@ -3723,8 +3739,15 @@
|
||||
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac offchannel skb %pK len %d\n",
|
||||
skb, skb->len);
|
||||
|
||||
- hdr = (struct ieee80211_hdr *)skb->data;
|
||||
- peer_addr = ieee80211_get_DA(hdr);
|
||||
+ info = IEEE80211_SKB_CB(skb);
|
||||
+
|
||||
+ if (info->control.flags & IEEE80211_TX_CTRL_HW_80211_ENCAP) {
|
||||
+ peer_addr = skb->data;
|
||||
+ } else {
|
||||
+ hdr = (struct ieee80211_hdr *)skb->data;
|
||||
+ peer_addr = ieee80211_get_DA(hdr);
|
||||
+ }
|
||||
+
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
vdev_id = ar->scan.vdev_id;
|
||||
@@ -4198,7 +4221,7 @@
|
||||
struct ieee80211_vif *vif = info->control.vif;
|
||||
struct ieee80211_sta *sta = control->sta;
|
||||
struct ieee80211_txq *txq = NULL;
|
||||
- struct ieee80211_hdr *hdr = (void *)skb->data;
|
||||
+ struct ieee80211_hdr *hdr;
|
||||
enum ath10k_hw_txrx_mode txmode;
|
||||
enum ath10k_mac_tx_path txpath;
|
||||
bool is_htt;
|
||||
@@ -4227,14 +4250,20 @@
|
||||
return;
|
||||
}
|
||||
|
||||
- ret = ath10k_htt_tx_mgmt_inc_pending(htt, is_mgmt, is_presp);
|
||||
- if (ret) {
|
||||
- ath10k_dbg(ar, ATH10K_DBG_MAC, "failed to increase tx mgmt pending count: %d, dropping\n",
|
||||
- ret);
|
||||
- ath10k_htt_tx_dec_pending(htt);
|
||||
- spin_unlock_bh(&ar->htt.tx_lock);
|
||||
- ieee80211_free_txskb(ar->hw, skb);
|
||||
- return;
|
||||
+ if (is_mgmt) {
|
||||
+ hdr = (struct ieee80211_hdr *)skb->data;
|
||||
+ is_presp = ieee80211_is_probe_resp(hdr->frame_control);
|
||||
+
|
||||
+ ret = ath10k_htt_tx_mgmt_inc_pending(htt, is_mgmt,
|
||||
+ is_presp);
|
||||
+ if (ret) {
|
||||
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "failed to increase tx mgmt pending count: %d, dropping\n",
|
||||
+ ret);
|
||||
+ ath10k_htt_tx_dec_pending(htt);
|
||||
+ spin_unlock_bh(&ar->htt.tx_lock);
|
||||
+ ieee80211_free_txskb(ar->hw, skb);
|
||||
+ return;
|
||||
+ }
|
||||
}
|
||||
spin_unlock_bh(&ar->htt.tx_lock);
|
||||
}
|
||||
@@ -4929,10 +4958,12 @@
|
||||
static int ath10k_add_interface(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
+ struct wireless_dev *wdev = ieee80211_vif_to_wdev(vif);
|
||||
struct ath10k *ar = hw->priv;
|
||||
struct ath10k_vif *arvif = (void *)vif->drv_priv;
|
||||
struct ath10k_peer *peer;
|
||||
enum wmi_sta_powersave_param param;
|
||||
+ int hw_encap = 0;
|
||||
int ret = 0;
|
||||
u32 value;
|
||||
int bit;
|
||||
@@ -5023,6 +5054,21 @@
|
||||
WARN_ON(1);
|
||||
break;
|
||||
}
|
||||
+
|
||||
+ switch (vif->type) {
|
||||
+ case NL80211_IFTYPE_STATION:
|
||||
+ case NL80211_IFTYPE_AP_VLAN:
|
||||
+ if (wdev->netdev->ieee80211_ptr->use_4addr)
|
||||
+ break;
|
||||
+ /* fall through */
|
||||
+ case NL80211_IFTYPE_AP:
|
||||
+ hw_encap = 1;
|
||||
+ break;
|
||||
+ default:
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ ieee80211_set_hw_80211_encap(vif, ar->ethernetmode & hw_encap);
|
||||
|
||||
/* Using vdev_id as queue number will make it very easy to do per-vif
|
||||
* tx queue locking. This shouldn't wrap due to interface combinations
|
||||
@@ -8208,6 +8254,8 @@
|
||||
ieee80211_hw_set(ar->hw, QUEUE_CONTROL);
|
||||
ieee80211_hw_set(ar->hw, SUPPORTS_TX_FRAG);
|
||||
ieee80211_hw_set(ar->hw, REPORTS_LOW_ACK);
|
||||
+ if (ar->ethernetmode)
|
||||
+ ieee80211_hw_set(ar->hw, SUPPORTS_80211_ENCAP);
|
||||
|
||||
if (!test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags))
|
||||
ieee80211_hw_set(ar->hw, SW_CRYPTO_CONTROL);
|
||||
diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c
|
||||
index 39abf8b12903..1d8a6c2571a1 100644
|
||||
--- a/drivers/net/wireless/ath/ath10k/txrx.c
|
||||
+++ b/drivers/net/wireless/ath/ath10k/txrx.c
|
||||
@@ -60,6 +60,8 @@ int ath10k_txrx_tx_unref(struct ath10k_htt *htt,
|
||||
struct ath10k_skb_cb *skb_cb;
|
||||
struct ath10k_txq *artxq;
|
||||
struct sk_buff *msdu;
|
||||
+ struct ieee80211_vif *vif;
|
||||
+ u8 flags;
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTT,
|
||||
"htt tx completion msdu_id %u status %d\n",
|
||||
@@ -88,6 +90,9 @@ int ath10k_txrx_tx_unref(struct ath10k_htt *htt,
|
||||
artxq->num_fw_queued--;
|
||||
}
|
||||
|
||||
+ flags = skb_cb->flags;
|
||||
+ vif = skb_cb->vif;
|
||||
+
|
||||
ath10k_htt_tx_free_msdu_id(htt, tx_done->msdu_id);
|
||||
ath10k_htt_tx_dec_pending(htt);
|
||||
if (htt->num_pending_tx == 0)
|
||||
@@ -119,7 +124,11 @@ int ath10k_txrx_tx_unref(struct ath10k_htt *htt,
|
||||
(info->flags & IEEE80211_TX_CTL_NO_ACK))
|
||||
info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED;
|
||||
|
||||
- ieee80211_tx_status(htt->ar->hw, msdu);
|
||||
+ if (flags & ATH10K_SKB_F_HW_80211_ENCAP)
|
||||
+ ieee80211_tx_status_8023(htt->ar->hw, vif, msdu);
|
||||
+ else
|
||||
+ ieee80211_tx_status(htt->ar->hw, msdu);
|
||||
+
|
||||
/* we do not own the msdu anymore */
|
||||
|
||||
return 0;
|
||||
@ -1,20 +0,0 @@
|
||||
--- a/arch/arm/boot/dts/qcom-ipq4019.dtsi
|
||||
+++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi
|
||||
@@ -387,7 +387,7 @@
|
||||
dma-names = "rx", "tx";
|
||||
};
|
||||
|
||||
- serial@78b0000 {
|
||||
+ blsp1_uart2: serial@78b0000 {
|
||||
compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
|
||||
reg = <0x78b0000 0x200>;
|
||||
interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
|
||||
@@ -591,7 +591,7 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
- mdio@90000 {
|
||||
+ mdio: mdio@90000 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "qcom,ipq4019-mdio";
|
||||
@ -1,12 +0,0 @@
|
||||
--- a/drivers/of/fdt.c
|
||||
+++ b/drivers/of/fdt.c
|
||||
@@ -1130,6 +1130,9 @@ int __init early_init_dt_scan_chosen(uns
|
||||
p = of_get_flat_dt_prop(node, "bootargs", &l);
|
||||
if (p != NULL && l > 0)
|
||||
strlcpy(data, p, min((int)l, COMMAND_LINE_SIZE));
|
||||
+ p = of_get_flat_dt_prop(node, "bootargs-append", &l);
|
||||
+ if (p != NULL && l > 0)
|
||||
+ strlcat(data, p, min_t(int, strlen(data) + (int)l, COMMAND_LINE_SIZE));
|
||||
|
||||
/*
|
||||
* CONFIG_CMDLINE is meant to be a default in case nothing else
|
||||
@ -1,73 +0,0 @@
|
||||
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
|
||||
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
|
||||
@@ -2329,7 +2329,7 @@ ath10k_update_per_peer_tx_stats(struct a
|
||||
sgi = ATH10K_HW_GI(peer_stats->flags);
|
||||
|
||||
if (txrate.flags == WMI_RATE_PREAMBLE_VHT && txrate.mcs > 9) {
|
||||
- ath10k_warn(ar, "Invalid VHT mcs %hhd peer stats", txrate.mcs);
|
||||
+
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2387,7 +2387,7 @@ static void ath10k_htt_fetch_peer_stats(
|
||||
ppdu_len = resp->peer_tx_stats.ppdu_len * sizeof(__le32);
|
||||
|
||||
if (skb->len < sizeof(struct htt_resp_hdr) + num_ppdu * ppdu_len) {
|
||||
- ath10k_warn(ar, "Invalid peer stats buf length %d\n", skb->len);
|
||||
+
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2399,8 +2399,8 @@ static void ath10k_htt_fetch_peer_stats(
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
peer = ath10k_peer_find_by_id(ar, peer_id);
|
||||
if (!peer) {
|
||||
- ath10k_warn(ar, "Invalid peer id %d peer stats buffer\n",
|
||||
- peer_id);
|
||||
+
|
||||
+
|
||||
goto out;
|
||||
}
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath10k/txrx.c
|
||||
+++ b/drivers/net/wireless/ath/ath10k/txrx.c
|
||||
@@ -250,8 +250,8 @@ void ath10k_peer_unmap_event(struct ath1
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
peer = ath10k_peer_find_by_id(ar, ev->peer_id);
|
||||
if (!peer) {
|
||||
- ath10k_warn(ar, "peer-unmap-event: unknown peer id %d\n",
|
||||
- ev->peer_id);
|
||||
+
|
||||
+
|
||||
goto exit;
|
||||
}
|
||||
|
||||
--- a/drivers/base/firmware_class.c
|
||||
+++ b/drivers/base/firmware_class.c
|
||||
@@ -1218,10 +1218,10 @@ _request_firmware(const struct firmware
|
||||
if (ret) {
|
||||
if (!(opt_flags & FW_OPT_NO_WARN))
|
||||
dev_warn(device,
|
||||
- "Direct firmware load for %s failed with error %d\n",
|
||||
- name, ret);
|
||||
+ "Direct firmware load for %s \n",
|
||||
+ name);
|
||||
if (opt_flags & FW_OPT_USERHELPER) {
|
||||
- dev_warn(device, "Falling back to user helper\n");
|
||||
+ dev_warn(device, "Load Wireless ART files\n");
|
||||
ret = fw_load_from_user_helper(fw, name, device,
|
||||
opt_flags);
|
||||
}
|
||||
--- a/drivers/net/wireless/ath/ath10k/sdio.c
|
||||
+++ b/drivers/net/wireless/ath/ath10k/sdio.c
|
||||
@@ -1874,8 +1874,8 @@ static int ath10k_sdio_hif_map_service_t
|
||||
ar_sdio->mbox_addr[eid], ar_sdio->mbox_size[eid]);
|
||||
break;
|
||||
default:
|
||||
- ath10k_warn(ar, "unsupported HTC service id: %d\n",
|
||||
- service_id);
|
||||
+
|
||||
+
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -1,34 +0,0 @@
|
||||
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
|
||||
index 24e1ea3..b1ff69a 100644
|
||||
--- a/drivers/mtd/devices/m25p80.c
|
||||
+++ b/drivers/mtd/devices/m25p80.c
|
||||
@@ -313,6 +313,21 @@ static int m25p_remove(struct spi_device *spi)
|
||||
return mtd_device_unregister(&flash->spi_nor.mtd);
|
||||
}
|
||||
|
||||
+static void m25p_shutdown(struct spi_device *spi)
|
||||
+{
|
||||
+ struct m25p *flash = spi_get_drvdata(spi);
|
||||
+
|
||||
+ if ((&flash->spi_nor)->addr_width > 3) {
|
||||
+ printk(KERN_INFO "m25p80: exit 4-byte address mode\n");
|
||||
+ flash->command[0] = SPINOR_OP_EX4B; // exit 4-byte address mode: 0xe9
|
||||
+ spi_write(flash->spi, flash->command, 1);
|
||||
+ flash->command[0] = 0x66; // enable reset
|
||||
+ spi_write(flash->spi, flash->command, 1);
|
||||
+ flash->command[0] = 0x99; // reset
|
||||
+ spi_write(flash->spi, flash->command, 1);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* Do NOT add to this array without reading the following:
|
||||
*
|
||||
@@ -387,6 +402,7 @@ static struct spi_driver m25p80_driver = {
|
||||
.id_table = m25p_ids,
|
||||
.probe = m25p_probe,
|
||||
.remove = m25p_remove,
|
||||
+ .shutdown = m25p_shutdown,
|
||||
|
||||
/* REVISIT: many of these chips have deep power-down modes, which
|
||||
* should clearly be entered on suspend() to minimize power use.
|
||||
Loading…
Reference in New Issue
Block a user