mirror of https://github.com/hak5/openwrt.git
apm821xx: remove 4.4 kernel support
Signed-off-by: Christian Lamparter <chunkeey@googlemail.com>openwrt-18.06
parent
51397d7d95
commit
cead8f9dfd
|
@ -1,331 +0,0 @@
|
|||
# CONFIG_40x is not set
|
||||
CONFIG_44x=y
|
||||
CONFIG_4xx=y
|
||||
CONFIG_4xx_SOC=y
|
||||
# CONFIG_ADVANCED_OPTIONS is not set
|
||||
CONFIG_APM821xx=y
|
||||
# CONFIG_APOLLO3G is not set
|
||||
# CONFIG_ARCHES is not set
|
||||
CONFIG_ARCH_DMA_ADDR_T_64BIT=y
|
||||
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
|
||||
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
|
||||
CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
|
||||
CONFIG_ARCH_HAS_DMA_SET_COHERENT_MASK=y
|
||||
CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
|
||||
CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y
|
||||
CONFIG_ARCH_HAS_ILOG2_U32=y
|
||||
CONFIG_ARCH_HAS_SG_CHAIN=y
|
||||
CONFIG_ARCH_HAS_WALK_MEMORY=y
|
||||
CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y
|
||||
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
|
||||
CONFIG_ARCH_MAY_HAVE_PC_FDC=y
|
||||
CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
|
||||
CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y
|
||||
CONFIG_ARCH_PHYS_ADDR_T_64BIT=y
|
||||
# CONFIG_ARCH_RANDOM is not set
|
||||
CONFIG_ARCH_REQUIRE_GPIOLIB=y
|
||||
CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y
|
||||
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
|
||||
CONFIG_ARCH_SUPPORTS_UPROBES=y
|
||||
CONFIG_ARCH_SUSPEND_POSSIBLE=y
|
||||
CONFIG_ARCH_USE_BUILTIN_BSWAP=y
|
||||
CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
|
||||
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
|
||||
CONFIG_AUDIT_ARCH=y
|
||||
# CONFIG_BAMBOO is not set
|
||||
CONFIG_BCH=y
|
||||
# CONFIG_BLUESTONE is not set
|
||||
CONFIG_BUCKMINSTER=y
|
||||
CONFIG_BOOKE=y
|
||||
CONFIG_BOOKE_WDT=y
|
||||
CONFIG_BOUNCE=y
|
||||
# CONFIG_CANYONLANDS is not set
|
||||
# CONFIG_IKAREM is not set
|
||||
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
|
||||
CONFIG_CLONE_BACKWARDS=y
|
||||
CONFIG_CMDLINE="rootfstype=squashfs noinitrd"
|
||||
CONFIG_CMDLINE_BOOL=y
|
||||
CONFIG_CONSISTENT_SIZE=0x00200000
|
||||
CONFIG_CPU_BIG_ENDIAN=y
|
||||
# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
|
||||
CONFIG_CRC16=y
|
||||
CONFIG_CRYPTO_DEFLATE=y
|
||||
CONFIG_CRYPTO_DEV_PPC4XX=y
|
||||
CONFIG_CRYPTO_HASH=y
|
||||
CONFIG_CRYPTO_HASH2=y
|
||||
CONFIG_CRYPTO_HW=y
|
||||
CONFIG_CRYPTO_LZO=y
|
||||
CONFIG_CRYPTO_MD5_PPC=y
|
||||
CONFIG_CRYPTO_RNG2=y
|
||||
CONFIG_CRYPTO_SHA1_PPC=y
|
||||
CONFIG_CRYPTO_WORKQUEUE=y
|
||||
CONFIG_DECOMPRESS_GZIP=y
|
||||
# CONFIG_DEFAULT_UIMAGE is not set
|
||||
CONFIG_DTC=y
|
||||
# CONFIG_E200 is not set
|
||||
CONFIG_EARLY_PRINTK=y
|
||||
# CONFIG_EBONY is not set
|
||||
CONFIG_EDAC_ATOMIC_SCRUB=y
|
||||
CONFIG_EDAC_SUPPORT=y
|
||||
# CONFIG_EIGER is not set
|
||||
# CONFIG_EPAPR_BOOT is not set
|
||||
CONFIG_EXTRA_TARGETS="uImage"
|
||||
CONFIG_FREEZER=y
|
||||
# CONFIG_FSL_ULI1575 is not set
|
||||
CONFIG_GENERIC_ATOMIC64=y
|
||||
CONFIG_GENERIC_BUG=y
|
||||
CONFIG_GENERIC_CLOCKEVENTS=y
|
||||
CONFIG_GENERIC_CMOS_UPDATE=y
|
||||
# CONFIG_GENERIC_CSUM is not set
|
||||
CONFIG_GENERIC_IO=y
|
||||
CONFIG_GENERIC_IRQ_SHOW=y
|
||||
CONFIG_GENERIC_IRQ_SHOW_LEVEL=y
|
||||
CONFIG_GENERIC_ISA_DMA=y
|
||||
CONFIG_GENERIC_MSI_IRQ=y
|
||||
CONFIG_GENERIC_NVRAM=y
|
||||
CONFIG_GENERIC_PCI_IOMAP=y
|
||||
CONFIG_GENERIC_SMP_IDLE_THREAD=y
|
||||
CONFIG_GENERIC_STRNCPY_FROM_USER=y
|
||||
CONFIG_GENERIC_STRNLEN_USER=y
|
||||
# CONFIG_GENERIC_TBSYNC is not set
|
||||
CONFIG_GENERIC_TIME_VSYSCALL_OLD=y
|
||||
# CONFIG_GEN_RTC is not set
|
||||
# CONFIG_GE_FPGA is not set
|
||||
# CONFIG_GLACIER is not set
|
||||
CONFIG_GLOB=y
|
||||
CONFIG_GPIOLIB=y
|
||||
CONFIG_GPIO_DEVRES=y
|
||||
CONFIG_GPIO_GENERIC=y
|
||||
CONFIG_GPIO_GENERIC_PLATFORM=y
|
||||
CONFIG_GPIO_SYSFS=y
|
||||
CONFIG_HAS_DMA=y
|
||||
CONFIG_HAS_IOMEM=y
|
||||
CONFIG_HAS_IOPORT_MAP=y
|
||||
# CONFIG_HAS_RAPIDIO is not set
|
||||
# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
|
||||
CONFIG_HAVE_ARCH_AUDITSYSCALL=y
|
||||
# CONFIG_HAVE_ARCH_BITREVERSE is not set
|
||||
CONFIG_HAVE_ARCH_JUMP_LABEL=y
|
||||
CONFIG_HAVE_ARCH_KGDB=y
|
||||
CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
|
||||
CONFIG_HAVE_ARCH_TRACEHOOK=y
|
||||
# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
|
||||
CONFIG_HAVE_BPF_JIT=y
|
||||
CONFIG_HAVE_DEBUG_KMEMLEAK=y
|
||||
CONFIG_HAVE_DEBUG_STACKOVERFLOW=y
|
||||
CONFIG_HAVE_DMA_API_DEBUG=y
|
||||
CONFIG_HAVE_DMA_ATTRS=y
|
||||
CONFIG_HAVE_DYNAMIC_FTRACE=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 is not set
|
||||
CONFIG_HAVE_GENERIC_RCU_GUP=y
|
||||
CONFIG_HAVE_IDE=y
|
||||
CONFIG_HAVE_IOREMAP_PROT=y
|
||||
CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK=y
|
||||
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
|
||||
CONFIG_HAVE_MEMBLOCK=y
|
||||
CONFIG_HAVE_MEMBLOCK_NODE_MAP=y
|
||||
CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
|
||||
CONFIG_HAVE_NET_DSA=y
|
||||
CONFIG_HAVE_OPROFILE=y
|
||||
CONFIG_HAVE_PERF_EVENTS=y
|
||||
CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
|
||||
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
|
||||
CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
|
||||
CONFIG_HW_RANDOM=y
|
||||
CONFIG_HW_RANDOM_PPC4XX=y
|
||||
CONFIG_HZ=1000
|
||||
# CONFIG_HZ_100 is not set
|
||||
CONFIG_HZ_1000=y
|
||||
CONFIG_HZ_PERIODIC=y
|
||||
CONFIG_I2C=y
|
||||
CONFIG_I2C_BOARDINFO=y
|
||||
CONFIG_I2C_CHARDEV=y
|
||||
CONFIG_I2C_IBM_IIC=y
|
||||
CONFIG_IBM_EMAC=y
|
||||
CONFIG_IBM_EMAC_EMAC4=y
|
||||
CONFIG_IBM_EMAC_POLL_WEIGHT=32
|
||||
CONFIG_IBM_EMAC_RGMII=y
|
||||
CONFIG_IBM_EMAC_RXB=128
|
||||
CONFIG_IBM_EMAC_RX_COPY_THRESHOLD=256
|
||||
CONFIG_IBM_EMAC_RX_SKB_HEADROOM=0
|
||||
CONFIG_IBM_EMAC_TAH=y
|
||||
CONFIG_IBM_EMAC_TXB=128
|
||||
# CONFIG_ICON is not set
|
||||
CONFIG_INITRAMFS_SOURCE=""
|
||||
# CONFIG_IOMMU_HELPER is not set
|
||||
# CONFIG_IPIC is not set
|
||||
CONFIG_IRQCHIP=y
|
||||
CONFIG_IRQ_DOMAIN=y
|
||||
CONFIG_IRQ_FORCED_THREADING=y
|
||||
CONFIG_IRQ_WORK=y
|
||||
CONFIG_ISA_DMA_API=y
|
||||
# CONFIG_KATMAI is not set
|
||||
CONFIG_KERNEL_START=0xc0000000
|
||||
CONFIG_LIBFDT=y
|
||||
CONFIG_LOWMEM_SIZE=0x30000000
|
||||
CONFIG_LZO_COMPRESS=y
|
||||
CONFIG_LZO_DECOMPRESS=y
|
||||
# CONFIG_MATH_EMULATION is not set
|
||||
CONFIG_MDIO_BOARDINFO=y
|
||||
# CONFIG_MMIO_NVRAM is not set
|
||||
CONFIG_MODULES_USE_ELF_RELA=y
|
||||
# CONFIG_MPIC is not set
|
||||
# CONFIG_MPIC_U3_HT_IRQS is not set
|
||||
# CONFIG_MPIC_WEIRD is not set
|
||||
CONFIG_MTD_CFI_ADV_OPTIONS=y
|
||||
# CONFIG_MTD_CFI_GEOMETRY is not set
|
||||
CONFIG_MTD_NAND=y
|
||||
CONFIG_MTD_NAND_BCH=y
|
||||
CONFIG_MTD_NAND_ECC=y
|
||||
CONFIG_MTD_NAND_ECC_BCH=y
|
||||
CONFIG_MTD_NAND_ECC_SMC=y
|
||||
CONFIG_MTD_NAND_NDFC=y
|
||||
# CONFIG_MTD_SPLIT is not set
|
||||
# CONFIG_MTD_SPLIT_FIRMWARE_NAME is not set
|
||||
# CONFIG_MTD_SPLIT_SQUASHFS_ROOT is not set
|
||||
# CONFIG_MTD_SPLIT_SUPPORT is not set
|
||||
# CONFIG_MTD_UBI is not set
|
||||
# CONFIG_MTD_UBI_BEB_LIMIT is not set
|
||||
# CONFIG_MTD_UBI_BLOCK is not set
|
||||
# CONFIG_MTD_UBI_FASTMAP is not set
|
||||
# CONFIG_MTD_UBI_GLUEBI is not set
|
||||
# CONFIG_MTD_UBI_WL_THRESHOLD is not set
|
||||
CONFIG_NEED_DMA_MAP_STATE=y
|
||||
# CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK is not set
|
||||
CONFIG_NEED_PER_CPU_KM=y
|
||||
CONFIG_NEED_SG_DMA_LENGTH=y
|
||||
# CONFIG_NONSTATIC_KERNEL is not set
|
||||
CONFIG_NOT_COHERENT_CACHE=y
|
||||
CONFIG_NO_BOOTMEM=y
|
||||
CONFIG_NR_IRQS=512
|
||||
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_MTD=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_SIGSUSPEND=y
|
||||
CONFIG_PAGE_OFFSET=0xc0000000
|
||||
CONFIG_PCI=y
|
||||
CONFIG_PCIEAER=y
|
||||
CONFIG_PCIEPORTBUS=y
|
||||
CONFIG_PCIE_PME=y
|
||||
CONFIG_PCI_BUS_ADDR_T_64BIT=y
|
||||
CONFIG_PCI_DISABLE_COMMON_QUIRKS=y
|
||||
CONFIG_PCI_DOMAINS=y
|
||||
CONFIG_PCI_MSI=y
|
||||
CONFIG_PGTABLE_LEVELS=2
|
||||
CONFIG_PHYLIB=y
|
||||
CONFIG_PHYSICAL_START=0x00000000
|
||||
CONFIG_PHYS_64BIT=y
|
||||
CONFIG_PHYS_ADDR_T_64BIT=y
|
||||
CONFIG_PM=y
|
||||
CONFIG_PM_AUTOSLEEP=y
|
||||
# CONFIG_PM_DEBUG is not set
|
||||
CONFIG_PM_SLEEP=y
|
||||
CONFIG_PM_WAKELOCKS=y
|
||||
CONFIG_PM_WAKELOCKS_GC=y
|
||||
CONFIG_PM_WAKELOCKS_LIMIT=100
|
||||
CONFIG_PPC=y
|
||||
CONFIG_PPC32=y
|
||||
# CONFIG_PPC44x_SIMPLE is not set
|
||||
CONFIG_PPC4xx_CPM=y
|
||||
CONFIG_PPC4xx_GPIO=y
|
||||
# CONFIG_PPC4xx_HSTA_MSI is not set
|
||||
# CONFIG_PPC4xx_MSI is not set
|
||||
CONFIG_PPC4xx_OCM=y
|
||||
# CONFIG_PPC4xx_PCI_EXPRESS is not set
|
||||
# CONFIG_PPC64 is not set
|
||||
# CONFIG_PPC_47x is not set
|
||||
# CONFIG_PPC_85xx is not set
|
||||
# CONFIG_PPC_8xx is not set
|
||||
# CONFIG_PPC_970_NAP is not set
|
||||
CONFIG_PPC_ADV_DEBUG_DACS=2
|
||||
CONFIG_PPC_ADV_DEBUG_DAC_RANGE=y
|
||||
CONFIG_PPC_ADV_DEBUG_DVCS=2
|
||||
CONFIG_PPC_ADV_DEBUG_IACS=4
|
||||
CONFIG_PPC_ADV_DEBUG_REGS=y
|
||||
# CONFIG_PPC_BOOK3S_32 is not set
|
||||
# CONFIG_PPC_CELL is not set
|
||||
# CONFIG_PPC_CELL_NATIVE is not set
|
||||
# CONFIG_PPC_COPRO_BASE is not set
|
||||
CONFIG_PPC_DCR=y
|
||||
# CONFIG_PPC_DCR_MMIO is not set
|
||||
CONFIG_PPC_DCR_NATIVE=y
|
||||
# CONFIG_PPC_DOORBELL is not set
|
||||
# CONFIG_PPC_EARLY_DEBUG is not set
|
||||
# CONFIG_PPC_EPAPR_HV_PIC is not set
|
||||
CONFIG_PPC_FPU=y
|
||||
# CONFIG_PPC_I8259 is not set
|
||||
# CONFIG_PPC_ICP_HV is not set
|
||||
# CONFIG_PPC_ICP_NATIVE is not set
|
||||
# CONFIG_PPC_ICS_RTAS is not set
|
||||
CONFIG_PPC_INDIRECT_PCI=y
|
||||
CONFIG_PPC_LIB_RHEAP=y
|
||||
CONFIG_PPC_MMU_NOHASH=y
|
||||
# CONFIG_PPC_MM_SLICES is not set
|
||||
# CONFIG_PPC_MPC106 is not set
|
||||
# CONFIG_PPC_MSI_BITMAP is not set
|
||||
# CONFIG_PPC_P7_NAP is not set
|
||||
CONFIG_PPC_PCI_CHOICE=y
|
||||
# CONFIG_PPC_RTAS is not set
|
||||
CONFIG_PPC_UDBG_16550=y
|
||||
CONFIG_PPC_WERROR=y
|
||||
# CONFIG_PPC_XICS is not set
|
||||
# CONFIG_PQ2ADS is not set
|
||||
CONFIG_PTE_64BIT=y
|
||||
# CONFIG_RAINIER is not set
|
||||
CONFIG_RAS=y
|
||||
# CONFIG_RCU_STALL_COMMON is not set
|
||||
CONFIG_RD_GZIP=y
|
||||
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
|
||||
# CONFIG_SAM440EP is not set
|
||||
CONFIG_SCHED_HRTICK=y
|
||||
# CONFIG_SCHED_INFO is not set
|
||||
# CONFIG_SCSI_DMA is not set
|
||||
# CONFIG_SEQUOIA is not set
|
||||
CONFIG_SERIAL_8250_EXTENDED=y
|
||||
CONFIG_SERIAL_8250_FSL=y
|
||||
CONFIG_SERIAL_8250_SHARE_IRQ=y
|
||||
CONFIG_SERIAL_OF_PLATFORM=y
|
||||
CONFIG_SIMPLE_GPIO=y
|
||||
CONFIG_SPARSE_IRQ=y
|
||||
CONFIG_SRCU=y
|
||||
# CONFIG_STRICT_MM_TYPECHECKS is not set
|
||||
CONFIG_SUSPEND=y
|
||||
CONFIG_SUSPEND_FREEZER=y
|
||||
# CONFIG_SWIOTLB is not set
|
||||
CONFIG_SYSCTL_EXCEPTION_TRACE=y
|
||||
# CONFIG_TAISHAN is not set
|
||||
CONFIG_TASK_SIZE=0xc0000000
|
||||
CONFIG_TICK_CPU_ACCOUNTING=y
|
||||
# CONFIG_UBIFS_FS is not set
|
||||
# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set
|
||||
# CONFIG_UBIFS_FS_LZO is not set
|
||||
# CONFIG_UBIFS_FS_ZLIB is not set
|
||||
CONFIG_USB_SUPPORT=y
|
||||
CONFIG_VDSO32=y
|
||||
# CONFIG_WARP is not set
|
||||
# CONFIG_WNDR4700 is not set
|
||||
CONFIG_WORD_SIZE=32
|
||||
# CONFIG_XILINX_SYSACE is not set
|
||||
# CONFIG_XILINX_VIRTEX440_GENERIC_BOARD is not set
|
||||
CONFIG_XZ_DEC_BCJ=y
|
||||
CONFIG_XZ_DEC_POWERPC=y
|
||||
# CONFIG_YOSEMITE is not set
|
||||
CONFIG_ZLIB_DEFLATE=y
|
||||
CONFIG_ZLIB_INFLATE=y
|
||||
# CONFIG_JFFS2_FS is not set
|
||||
# CONFIG_SENSORS_TC654 is not set
|
|
@ -1,481 +0,0 @@
|
|||
From 5343e674f32fb82b7a80a24b5a84eee62d3fe624 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Lamparter <chunkeey@googlemail.com>
|
||||
Date: Mon, 18 Apr 2016 12:57:41 +0200
|
||||
Subject: [PATCH] crypto4xx: integrate ppc4xx-rng into crypto4xx
|
||||
|
||||
This patch integrates the ppc4xx-rng driver into the existing
|
||||
crypto4xx. This is because the true random number generator
|
||||
is controlled and part of the security core.
|
||||
|
||||
Signed-off-by: Christian Lamparter <chunkeey@googlemail.com>
|
||||
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
|
||||
---
|
||||
drivers/char/hw_random/Kconfig | 13 ---
|
||||
drivers/char/hw_random/Makefile | 1 -
|
||||
drivers/char/hw_random/ppc4xx-rng.c | 147 --------------------------------
|
||||
drivers/crypto/Kconfig | 8 ++
|
||||
drivers/crypto/amcc/Makefile | 1 +
|
||||
drivers/crypto/amcc/crypto4xx_core.c | 7 +-
|
||||
drivers/crypto/amcc/crypto4xx_core.h | 4 +
|
||||
drivers/crypto/amcc/crypto4xx_reg_def.h | 1 +
|
||||
drivers/crypto/amcc/crypto4xx_trng.c | 131 ++++++++++++++++++++++++++++
|
||||
drivers/crypto/amcc/crypto4xx_trng.h | 34 ++++++++
|
||||
10 files changed, 184 insertions(+), 163 deletions(-)
|
||||
delete mode 100644 drivers/char/hw_random/ppc4xx-rng.c
|
||||
create mode 100644 drivers/crypto/amcc/crypto4xx_trng.c
|
||||
create mode 100644 drivers/crypto/amcc/crypto4xx_trng.h
|
||||
|
||||
--- a/drivers/char/hw_random/Kconfig
|
||||
+++ b/drivers/char/hw_random/Kconfig
|
||||
@@ -268,19 +268,6 @@ config HW_RANDOM_NOMADIK
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
-config HW_RANDOM_PPC4XX
|
||||
- tristate "PowerPC 4xx generic true random number generator support"
|
||||
- depends on PPC && 4xx
|
||||
- default HW_RANDOM
|
||||
- ---help---
|
||||
- This driver provides the kernel-side support for the TRNG hardware
|
||||
- found in the security function of some PowerPC 4xx SoCs.
|
||||
-
|
||||
- To compile this driver as a module, choose M here: the
|
||||
- module will be called ppc4xx-rng.
|
||||
-
|
||||
- If unsure, say N.
|
||||
-
|
||||
config HW_RANDOM_PSERIES
|
||||
tristate "pSeries HW Random Number Generator support"
|
||||
depends on PPC64 && IBMVIO
|
||||
--- a/drivers/char/hw_random/Makefile
|
||||
+++ b/drivers/char/hw_random/Makefile
|
||||
@@ -22,7 +22,6 @@ obj-$(CONFIG_HW_RANDOM_TX4939) += tx4939
|
||||
obj-$(CONFIG_HW_RANDOM_MXC_RNGA) += mxc-rnga.o
|
||||
obj-$(CONFIG_HW_RANDOM_OCTEON) += octeon-rng.o
|
||||
obj-$(CONFIG_HW_RANDOM_NOMADIK) += nomadik-rng.o
|
||||
-obj-$(CONFIG_HW_RANDOM_PPC4XX) += ppc4xx-rng.o
|
||||
obj-$(CONFIG_HW_RANDOM_PSERIES) += pseries-rng.o
|
||||
obj-$(CONFIG_HW_RANDOM_POWERNV) += powernv-rng.o
|
||||
obj-$(CONFIG_HW_RANDOM_EXYNOS) += exynos-rng.o
|
||||
--- a/drivers/char/hw_random/ppc4xx-rng.c
|
||||
+++ /dev/null
|
||||
@@ -1,147 +0,0 @@
|
||||
-/*
|
||||
- * Generic PowerPC 44x RNG driver
|
||||
- *
|
||||
- * Copyright 2011 IBM Corporation
|
||||
- *
|
||||
- * 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; version 2 of the License.
|
||||
- */
|
||||
-
|
||||
-#include <linux/module.h>
|
||||
-#include <linux/kernel.h>
|
||||
-#include <linux/platform_device.h>
|
||||
-#include <linux/hw_random.h>
|
||||
-#include <linux/delay.h>
|
||||
-#include <linux/of_address.h>
|
||||
-#include <linux/of_platform.h>
|
||||
-#include <asm/io.h>
|
||||
-
|
||||
-#define PPC4XX_TRNG_DEV_CTRL 0x60080
|
||||
-
|
||||
-#define PPC4XX_TRNGE 0x00020000
|
||||
-#define PPC4XX_TRNG_CTRL 0x0008
|
||||
-#define PPC4XX_TRNG_CTRL_DALM 0x20
|
||||
-#define PPC4XX_TRNG_STAT 0x0004
|
||||
-#define PPC4XX_TRNG_STAT_B 0x1
|
||||
-#define PPC4XX_TRNG_DATA 0x0000
|
||||
-
|
||||
-#define MODULE_NAME "ppc4xx_rng"
|
||||
-
|
||||
-static int ppc4xx_rng_data_present(struct hwrng *rng, int wait)
|
||||
-{
|
||||
- void __iomem *rng_regs = (void __iomem *) rng->priv;
|
||||
- int busy, i, present = 0;
|
||||
-
|
||||
- for (i = 0; i < 20; i++) {
|
||||
- busy = (in_le32(rng_regs + PPC4XX_TRNG_STAT) & PPC4XX_TRNG_STAT_B);
|
||||
- if (!busy || !wait) {
|
||||
- present = 1;
|
||||
- break;
|
||||
- }
|
||||
- udelay(10);
|
||||
- }
|
||||
- return present;
|
||||
-}
|
||||
-
|
||||
-static int ppc4xx_rng_data_read(struct hwrng *rng, u32 *data)
|
||||
-{
|
||||
- void __iomem *rng_regs = (void __iomem *) rng->priv;
|
||||
- *data = in_le32(rng_regs + PPC4XX_TRNG_DATA);
|
||||
- return 4;
|
||||
-}
|
||||
-
|
||||
-static int ppc4xx_rng_enable(int enable)
|
||||
-{
|
||||
- struct device_node *ctrl;
|
||||
- void __iomem *ctrl_reg;
|
||||
- int err = 0;
|
||||
- u32 val;
|
||||
-
|
||||
- /* Find the main crypto device node and map it to turn the TRNG on */
|
||||
- ctrl = of_find_compatible_node(NULL, NULL, "amcc,ppc4xx-crypto");
|
||||
- if (!ctrl)
|
||||
- return -ENODEV;
|
||||
-
|
||||
- ctrl_reg = of_iomap(ctrl, 0);
|
||||
- if (!ctrl_reg) {
|
||||
- err = -ENODEV;
|
||||
- goto out;
|
||||
- }
|
||||
-
|
||||
- val = in_le32(ctrl_reg + PPC4XX_TRNG_DEV_CTRL);
|
||||
-
|
||||
- if (enable)
|
||||
- val |= PPC4XX_TRNGE;
|
||||
- else
|
||||
- val = val & ~PPC4XX_TRNGE;
|
||||
-
|
||||
- out_le32(ctrl_reg + PPC4XX_TRNG_DEV_CTRL, val);
|
||||
- iounmap(ctrl_reg);
|
||||
-
|
||||
-out:
|
||||
- of_node_put(ctrl);
|
||||
-
|
||||
- return err;
|
||||
-}
|
||||
-
|
||||
-static struct hwrng ppc4xx_rng = {
|
||||
- .name = MODULE_NAME,
|
||||
- .data_present = ppc4xx_rng_data_present,
|
||||
- .data_read = ppc4xx_rng_data_read,
|
||||
-};
|
||||
-
|
||||
-static int ppc4xx_rng_probe(struct platform_device *dev)
|
||||
-{
|
||||
- void __iomem *rng_regs;
|
||||
- int err = 0;
|
||||
-
|
||||
- rng_regs = of_iomap(dev->dev.of_node, 0);
|
||||
- if (!rng_regs)
|
||||
- return -ENODEV;
|
||||
-
|
||||
- err = ppc4xx_rng_enable(1);
|
||||
- if (err)
|
||||
- return err;
|
||||
-
|
||||
- out_le32(rng_regs + PPC4XX_TRNG_CTRL, PPC4XX_TRNG_CTRL_DALM);
|
||||
- ppc4xx_rng.priv = (unsigned long) rng_regs;
|
||||
-
|
||||
- err = hwrng_register(&ppc4xx_rng);
|
||||
-
|
||||
- return err;
|
||||
-}
|
||||
-
|
||||
-static int ppc4xx_rng_remove(struct platform_device *dev)
|
||||
-{
|
||||
- void __iomem *rng_regs = (void __iomem *) ppc4xx_rng.priv;
|
||||
-
|
||||
- hwrng_unregister(&ppc4xx_rng);
|
||||
- ppc4xx_rng_enable(0);
|
||||
- iounmap(rng_regs);
|
||||
-
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
-static const struct of_device_id ppc4xx_rng_match[] = {
|
||||
- { .compatible = "ppc4xx-rng", },
|
||||
- { .compatible = "amcc,ppc460ex-rng", },
|
||||
- { .compatible = "amcc,ppc440epx-rng", },
|
||||
- {},
|
||||
-};
|
||||
-MODULE_DEVICE_TABLE(of, ppc4xx_rng_match);
|
||||
-
|
||||
-static struct platform_driver ppc4xx_rng_driver = {
|
||||
- .driver = {
|
||||
- .name = MODULE_NAME,
|
||||
- .of_match_table = ppc4xx_rng_match,
|
||||
- },
|
||||
- .probe = ppc4xx_rng_probe,
|
||||
- .remove = ppc4xx_rng_remove,
|
||||
-};
|
||||
-
|
||||
-module_platform_driver(ppc4xx_rng_driver);
|
||||
-
|
||||
-MODULE_LICENSE("GPL");
|
||||
-MODULE_AUTHOR("Josh Boyer <jwboyer@linux.vnet.ibm.com>");
|
||||
-MODULE_DESCRIPTION("HW RNG driver for PPC 4xx processors");
|
||||
--- a/drivers/crypto/Kconfig
|
||||
+++ b/drivers/crypto/Kconfig
|
||||
@@ -277,6 +277,14 @@ config CRYPTO_DEV_PPC4XX
|
||||
help
|
||||
This option allows you to have support for AMCC crypto acceleration.
|
||||
|
||||
+config HW_RANDOM_PPC4XX
|
||||
+ bool "PowerPC 4xx generic true random number generator support"
|
||||
+ depends on CRYPTO_DEV_PPC4XX && HW_RANDOM
|
||||
+ default y
|
||||
+ ---help---
|
||||
+ This option provides the kernel-side support for the TRNG hardware
|
||||
+ found in the security function of some PowerPC 4xx SoCs.
|
||||
+
|
||||
config CRYPTO_DEV_OMAP_SHAM
|
||||
tristate "Support for OMAP MD5/SHA1/SHA2 hw accelerator"
|
||||
depends on ARCH_OMAP2PLUS
|
||||
--- a/drivers/crypto/amcc/Makefile
|
||||
+++ b/drivers/crypto/amcc/Makefile
|
||||
@@ -1,2 +1,3 @@
|
||||
obj-$(CONFIG_CRYPTO_DEV_PPC4XX) += crypto4xx.o
|
||||
crypto4xx-y := crypto4xx_core.o crypto4xx_alg.o crypto4xx_sa.o
|
||||
+crypto4xx-$(CONFIG_HW_RANDOM_PPC4XX) += crypto4xx_trng.o
|
||||
--- a/drivers/crypto/amcc/crypto4xx_core.c
|
||||
+++ b/drivers/crypto/amcc/crypto4xx_core.c
|
||||
@@ -40,6 +40,7 @@
|
||||
#include "crypto4xx_reg_def.h"
|
||||
#include "crypto4xx_core.h"
|
||||
#include "crypto4xx_sa.h"
|
||||
+#include "crypto4xx_trng.h"
|
||||
|
||||
#define PPC4XX_SEC_VERSION_STR "0.5"
|
||||
|
||||
@@ -1221,6 +1222,7 @@ static int crypto4xx_probe(struct platfo
|
||||
if (rc)
|
||||
goto err_start_dev;
|
||||
|
||||
+ ppc4xx_trng_probe(core_dev);
|
||||
return 0;
|
||||
|
||||
err_start_dev:
|
||||
@@ -1248,6 +1250,8 @@ static int crypto4xx_remove(struct platf
|
||||
struct device *dev = &ofdev->dev;
|
||||
struct crypto4xx_core_device *core_dev = dev_get_drvdata(dev);
|
||||
|
||||
+ ppc4xx_trng_remove(core_dev);
|
||||
+
|
||||
free_irq(core_dev->irq, dev);
|
||||
irq_dispose_mapping(core_dev->irq);
|
||||
|
||||
@@ -1268,7 +1272,7 @@ MODULE_DEVICE_TABLE(of, crypto4xx_match)
|
||||
|
||||
static struct platform_driver crypto4xx_driver = {
|
||||
.driver = {
|
||||
- .name = "crypto4xx",
|
||||
+ .name = MODULE_NAME,
|
||||
.of_match_table = crypto4xx_match,
|
||||
},
|
||||
.probe = crypto4xx_probe,
|
||||
@@ -1280,4 +1284,3 @@ module_platform_driver(crypto4xx_driver)
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("James Hsiao <jhsiao@amcc.com>");
|
||||
MODULE_DESCRIPTION("Driver for AMCC PPC4xx crypto accelerator");
|
||||
-
|
||||
--- a/drivers/crypto/amcc/crypto4xx_core.h
|
||||
+++ b/drivers/crypto/amcc/crypto4xx_core.h
|
||||
@@ -24,6 +24,8 @@
|
||||
|
||||
#include <crypto/internal/hash.h>
|
||||
|
||||
+#define MODULE_NAME "crypto4xx"
|
||||
+
|
||||
#define PPC460SX_SDR0_SRST 0x201
|
||||
#define PPC405EX_SDR0_SRST 0x200
|
||||
#define PPC460EX_SDR0_SRST 0x201
|
||||
@@ -72,6 +74,7 @@ struct crypto4xx_device {
|
||||
char *name;
|
||||
u64 ce_phy_address;
|
||||
void __iomem *ce_base;
|
||||
+ void __iomem *trng_base;
|
||||
|
||||
void *pdr; /* base address of packet
|
||||
descriptor ring */
|
||||
@@ -106,6 +109,7 @@ struct crypto4xx_core_device {
|
||||
struct device *device;
|
||||
struct platform_device *ofdev;
|
||||
struct crypto4xx_device *dev;
|
||||
+ struct hwrng *trng;
|
||||
u32 int_status;
|
||||
u32 irq;
|
||||
struct tasklet_struct tasklet;
|
||||
--- a/drivers/crypto/amcc/crypto4xx_reg_def.h
|
||||
+++ b/drivers/crypto/amcc/crypto4xx_reg_def.h
|
||||
@@ -125,6 +125,7 @@
|
||||
#define PPC4XX_INTERRUPT_CLR 0x3ffff
|
||||
#define PPC4XX_PRNG_CTRL_AUTO_EN 0x3
|
||||
#define PPC4XX_DC_3DES_EN 1
|
||||
+#define PPC4XX_TRNG_EN 0x00020000
|
||||
#define PPC4XX_INT_DESCR_CNT 4
|
||||
#define PPC4XX_INT_TIMEOUT_CNT 0
|
||||
#define PPC4XX_INT_CFG 1
|
||||
--- /dev/null
|
||||
+++ b/drivers/crypto/amcc/crypto4xx_trng.c
|
||||
@@ -0,0 +1,131 @@
|
||||
+/*
|
||||
+ * Generic PowerPC 44x RNG driver
|
||||
+ *
|
||||
+ * Copyright 2011 IBM Corporation
|
||||
+ *
|
||||
+ * 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; version 2 of the License.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/interrupt.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/hw_random.h>
|
||||
+#include <linux/delay.h>
|
||||
+#include <linux/of_address.h>
|
||||
+#include <linux/of_platform.h>
|
||||
+#include <linux/io.h>
|
||||
+
|
||||
+#include "crypto4xx_core.h"
|
||||
+#include "crypto4xx_trng.h"
|
||||
+#include "crypto4xx_reg_def.h"
|
||||
+
|
||||
+#define PPC4XX_TRNG_CTRL 0x0008
|
||||
+#define PPC4XX_TRNG_CTRL_DALM 0x20
|
||||
+#define PPC4XX_TRNG_STAT 0x0004
|
||||
+#define PPC4XX_TRNG_STAT_B 0x1
|
||||
+#define PPC4XX_TRNG_DATA 0x0000
|
||||
+
|
||||
+static int ppc4xx_trng_data_present(struct hwrng *rng, int wait)
|
||||
+{
|
||||
+ struct crypto4xx_device *dev = (void *)rng->priv;
|
||||
+ int busy, i, present = 0;
|
||||
+
|
||||
+ for (i = 0; i < 20; i++) {
|
||||
+ busy = (in_le32(dev->trng_base + PPC4XX_TRNG_STAT) &
|
||||
+ PPC4XX_TRNG_STAT_B);
|
||||
+ if (!busy || !wait) {
|
||||
+ present = 1;
|
||||
+ break;
|
||||
+ }
|
||||
+ udelay(10);
|
||||
+ }
|
||||
+ return present;
|
||||
+}
|
||||
+
|
||||
+static int ppc4xx_trng_data_read(struct hwrng *rng, u32 *data)
|
||||
+{
|
||||
+ struct crypto4xx_device *dev = (void *)rng->priv;
|
||||
+ *data = in_le32(dev->trng_base + PPC4XX_TRNG_DATA);
|
||||
+ return 4;
|
||||
+}
|
||||
+
|
||||
+static void ppc4xx_trng_enable(struct crypto4xx_device *dev, bool enable)
|
||||
+{
|
||||
+ u32 device_ctrl;
|
||||
+
|
||||
+ device_ctrl = readl(dev->ce_base + CRYPTO4XX_DEVICE_CTRL);
|
||||
+ if (enable)
|
||||
+ device_ctrl |= PPC4XX_TRNG_EN;
|
||||
+ else
|
||||
+ device_ctrl &= ~PPC4XX_TRNG_EN;
|
||||
+ writel(device_ctrl, dev->ce_base + CRYPTO4XX_DEVICE_CTRL);
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id ppc4xx_trng_match[] = {
|
||||
+ { .compatible = "ppc4xx-rng", },
|
||||
+ { .compatible = "amcc,ppc460ex-rng", },
|
||||
+ { .compatible = "amcc,ppc440epx-rng", },
|
||||
+ {},
|
||||
+};
|
||||
+
|
||||
+void ppc4xx_trng_probe(struct crypto4xx_core_device *core_dev)
|
||||
+{
|
||||
+ struct crypto4xx_device *dev = core_dev->dev;
|
||||
+ struct device_node *trng = NULL;
|
||||
+ struct hwrng *rng = NULL;
|
||||
+ int err;
|
||||
+
|
||||
+ /* Find the TRNG device node and map it */
|
||||
+ trng = of_find_matching_node(NULL, ppc4xx_trng_match);
|
||||
+ if (!trng || !of_device_is_available(trng))
|
||||
+ return;
|
||||
+
|
||||
+ dev->trng_base = of_iomap(trng, 0);
|
||||
+ of_node_put(trng);
|
||||
+ if (!dev->trng_base)
|
||||
+ goto err_out;
|
||||
+
|
||||
+ rng = kzalloc(sizeof(*rng), GFP_KERNEL);
|
||||
+ if (!rng)
|
||||
+ goto err_out;
|
||||
+
|
||||
+ rng->name = MODULE_NAME;
|
||||
+ rng->data_present = ppc4xx_trng_data_present;
|
||||
+ rng->data_read = ppc4xx_trng_data_read;
|
||||
+ rng->priv = (unsigned long) dev;
|
||||
+ core_dev->trng = rng;
|
||||
+ ppc4xx_trng_enable(dev, true);
|
||||
+ out_le32(dev->trng_base + PPC4XX_TRNG_CTRL, PPC4XX_TRNG_CTRL_DALM);
|
||||
+ err = devm_hwrng_register(core_dev->device, core_dev->trng);
|
||||
+ if (err) {
|
||||
+ ppc4xx_trng_enable(dev, false);
|
||||
+ dev_err(core_dev->device, "failed to register hwrng (%d).\n",
|
||||
+ err);
|
||||
+ goto err_out;
|
||||
+ }
|
||||
+ return;
|
||||
+
|
||||
+err_out:
|
||||
+ of_node_put(trng);
|
||||
+ iounmap(dev->trng_base);
|
||||
+ kfree(rng);
|
||||
+ dev->trng_base = NULL;
|
||||
+ core_dev->trng = NULL;
|
||||
+}
|
||||
+
|
||||
+void ppc4xx_trng_remove(struct crypto4xx_core_device *core_dev)
|
||||
+{
|
||||
+ if (core_dev && core_dev->trng) {
|
||||
+ struct crypto4xx_device *dev = core_dev->dev;
|
||||
+
|
||||
+ devm_hwrng_unregister(core_dev->device, core_dev->trng);
|
||||
+ ppc4xx_trng_enable(dev, false);
|
||||
+ iounmap(dev->trng_base);
|
||||
+ kfree(core_dev->trng);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+MODULE_ALIAS("ppc4xx_rng");
|
||||
--- /dev/null
|
||||
+++ b/drivers/crypto/amcc/crypto4xx_trng.h
|
||||
@@ -0,0 +1,34 @@
|
||||
+/**
|
||||
+ * AMCC SoC PPC4xx Crypto Driver
|
||||
+ *
|
||||
+ * Copyright (c) 2008 Applied Micro Circuits Corporation.
|
||||
+ * All rights reserved. James Hsiao <jhsiao@amcc.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.
|
||||
+ *
|
||||
+ * This file defines the security context
|
||||
+ * associate format.
|
||||
+ */
|
||||
+
|
||||
+#ifndef __CRYPTO4XX_TRNG_H__
|
||||
+#define __CRYPTO4XX_TRNG_H__
|
||||
+
|
||||
+#ifdef CONFIG_HW_RANDOM_PPC4XX
|
||||
+void ppc4xx_trng_probe(struct crypto4xx_core_device *core_dev);
|
||||
+void ppc4xx_trng_remove(struct crypto4xx_core_device *core_dev);
|
||||
+#else
|
||||
+static inline void ppc4xx_trng_probe(
|
||||
+ struct crypto4xx_device *dev __maybe_unused) { }
|
||||
+static inline void ppc4xx_trng_remove(
|
||||
+ struct crypto4xx_device *dev __maybe_unused) { }
|
||||
+#endif
|
||||
+
|
||||
+#endif
|
|
@ -1,57 +0,0 @@
|
|||
From 0c13957a43a90b1522eb616f3c9967ec44e4da1d Mon Sep 17 00:00:00 2001
|
||||
From: Christian Lamparter <chunkeey@googlemail.com>
|
||||
Date: Tue, 3 May 2016 13:58:24 +0200
|
||||
Subject: [PATCH] drivers: net: emac: add Atheros AR8035 phy initialization
|
||||
code
|
||||
To: netdev@vger.kernel.org
|
||||
|
||||
This patch adds the phy initialization code for Qualcomm
|
||||
Atheros AR8035 phy. This configuration is found in the
|
||||
Cisco Meraki MR24.
|
||||
|
||||
Signed-off-by: Christian Lamparter <chunkeey@googlemail.com>
|
||||
---
|
||||
drivers/net/ethernet/ibm/emac/phy.c | 26 ++++++++++++++++++++++++++
|
||||
1 file changed, 26 insertions(+)
|
||||
|
||||
--- a/drivers/net/ethernet/ibm/emac/phy.c
|
||||
+++ b/drivers/net/ethernet/ibm/emac/phy.c
|
||||
@@ -470,12 +470,38 @@ static struct mii_phy_def m88e1112_phy_d
|
||||
.ops = &m88e1112_phy_ops,
|
||||
};
|
||||
|
||||
+static int ar8035_init(struct mii_phy *phy)
|
||||
+{
|
||||
+ phy_write(phy, 0x1d, 0x5); /* Address debug register 5 */
|
||||
+ phy_write(phy, 0x1e, 0x2d47); /* Value copied from u-boot */
|
||||
+ phy_write(phy, 0x1d, 0xb); /* Address hib ctrl */
|
||||
+ phy_write(phy, 0x1e, 0xbc20); /* Value copied from u-boot */
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static struct mii_phy_ops ar8035_phy_ops = {
|
||||
+ .init = ar8035_init,
|
||||
+ .setup_aneg = genmii_setup_aneg,
|
||||
+ .setup_forced = genmii_setup_forced,
|
||||
+ .poll_link = genmii_poll_link,
|
||||
+ .read_link = genmii_read_link,
|
||||
+};
|
||||
+
|
||||
+static struct mii_phy_def ar8035_phy_def = {
|
||||
+ .phy_id = 0x004dd070,
|
||||
+ .phy_id_mask = 0xfffffff0,
|
||||
+ .name = "Atheros 8035 Gigabit Ethernet",
|
||||
+ .ops = &ar8035_phy_ops,
|
||||
+};
|
||||
+
|
||||
static struct mii_phy_def *mii_phy_table[] = {
|
||||
&et1011c_phy_def,
|
||||
&cis8201_phy_def,
|
||||
&bcm5248_phy_def,
|
||||
&m88e1111_phy_def,
|
||||
&m88e1112_phy_def,
|
||||
+ &ar8035_phy_def,
|
||||
&genmii_phy_def,
|
||||
NULL
|
||||
};
|
|
@ -1,138 +0,0 @@
|
|||
From 7bd903c5ca47fde5ad52370a47776491813c772e Mon Sep 17 00:00:00 2001
|
||||
From: Peter Ujfalusi <peter.ujfalusi@ti.com>
|
||||
Date: Mon, 14 Dec 2015 22:47:39 +0200
|
||||
Subject: [PATCH 1/3] dmaengine: core: Move and merge the code paths using
|
||||
private_candidate
|
||||
|
||||
Channel matching with private_candidate() is used in two paths, the error
|
||||
checking is slightly different in them and they are duplicating code also.
|
||||
Move the code under find_candidate() to provide consistent execution and
|
||||
going to allow us to reuse this mode of channel lookup later.
|
||||
|
||||
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
|
||||
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
|
||||
Reviewed-by: Arnd Bergmann <arnd@arndb.de>
|
||||
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
|
||||
---
|
||||
drivers/dma/dmaengine.c | 81 +++++++++++++++++++++++++------------------------
|
||||
1 file changed, 42 insertions(+), 39 deletions(-)
|
||||
|
||||
--- a/drivers/dma/dmaengine.c
|
||||
+++ b/drivers/dma/dmaengine.c
|
||||
@@ -542,6 +542,42 @@ static struct dma_chan *private_candidat
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+static struct dma_chan *find_candidate(struct dma_device *device,
|
||||
+ const dma_cap_mask_t *mask,
|
||||
+ dma_filter_fn fn, void *fn_param)
|
||||
+{
|
||||
+ struct dma_chan *chan = private_candidate(mask, device, fn, fn_param);
|
||||
+ int err;
|
||||
+
|
||||
+ if (chan) {
|
||||
+ /* Found a suitable channel, try to grab, prep, and return it.
|
||||
+ * We first set DMA_PRIVATE to disable balance_ref_count as this
|
||||
+ * channel will not be published in the general-purpose
|
||||
+ * allocator
|
||||
+ */
|
||||
+ dma_cap_set(DMA_PRIVATE, device->cap_mask);
|
||||
+ device->privatecnt++;
|
||||
+ err = dma_chan_get(chan);
|
||||
+
|
||||
+ if (err) {
|
||||
+ if (err == -ENODEV) {
|
||||
+ pr_debug("%s: %s module removed\n", __func__,
|
||||
+ dma_chan_name(chan));
|
||||
+ list_del_rcu(&device->global_node);
|
||||
+ } else
|
||||
+ pr_debug("%s: failed to get %s: (%d)\n",
|
||||
+ __func__, dma_chan_name(chan), err);
|
||||
+
|
||||
+ if (--device->privatecnt == 0)
|
||||
+ dma_cap_clear(DMA_PRIVATE, device->cap_mask);
|
||||
+
|
||||
+ chan = ERR_PTR(err);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return chan ? chan : ERR_PTR(-EPROBE_DEFER);
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* dma_get_slave_channel - try to get specific channel exclusively
|
||||
* @chan: target channel
|
||||
@@ -580,7 +616,6 @@ struct dma_chan *dma_get_any_slave_chann
|
||||
{
|
||||
dma_cap_mask_t mask;
|
||||
struct dma_chan *chan;
|
||||
- int err;
|
||||
|
||||
dma_cap_zero(mask);
|
||||
dma_cap_set(DMA_SLAVE, mask);
|
||||
@@ -588,23 +623,11 @@ struct dma_chan *dma_get_any_slave_chann
|
||||
/* lock against __dma_request_channel */
|
||||
mutex_lock(&dma_list_mutex);
|
||||
|
||||
- chan = private_candidate(&mask, device, NULL, NULL);
|
||||
- if (chan) {
|
||||
- dma_cap_set(DMA_PRIVATE, device->cap_mask);
|
||||
- device->privatecnt++;
|
||||
- err = dma_chan_get(chan);
|
||||
- if (err) {
|
||||
- pr_debug("%s: failed to get %s: (%d)\n",
|
||||
- __func__, dma_chan_name(chan), err);
|
||||
- chan = NULL;
|
||||
- if (--device->privatecnt == 0)
|
||||
- dma_cap_clear(DMA_PRIVATE, device->cap_mask);
|
||||
- }
|
||||
- }
|
||||
+ chan = find_candidate(device, &mask, NULL, NULL);
|
||||
|
||||
mutex_unlock(&dma_list_mutex);
|
||||
|
||||
- return chan;
|
||||
+ return IS_ERR(chan) ? NULL : chan;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dma_get_any_slave_channel);
|
||||
|
||||
@@ -621,35 +644,15 @@ struct dma_chan *__dma_request_channel(c
|
||||
{
|
||||
struct dma_device *device, *_d;
|
||||
struct dma_chan *chan = NULL;
|
||||
- int err;
|
||||
|
||||
/* Find a channel */
|
||||
mutex_lock(&dma_list_mutex);
|
||||
list_for_each_entry_safe(device, _d, &dma_device_list, global_node) {
|
||||
- chan = private_candidate(mask, device, fn, fn_param);
|
||||
- if (chan) {
|
||||
- /* Found a suitable channel, try to grab, prep, and
|
||||
- * return it. We first set DMA_PRIVATE to disable
|
||||
- * balance_ref_count as this channel will not be
|
||||
- * published in the general-purpose allocator
|
||||
- */
|
||||
- dma_cap_set(DMA_PRIVATE, device->cap_mask);
|
||||
- device->privatecnt++;
|
||||
- err = dma_chan_get(chan);
|
||||
+ chan = find_candidate(device, mask, fn, fn_param);
|
||||
+ if (!IS_ERR(chan))
|
||||
+ break;
|
||||
|
||||
- if (err == -ENODEV) {
|
||||
- pr_debug("%s: %s module removed\n",
|
||||
- __func__, dma_chan_name(chan));
|
||||
- list_del_rcu(&device->global_node);
|
||||
- } else if (err)
|
||||
- pr_debug("%s: failed to get %s: (%d)\n",
|
||||
- __func__, dma_chan_name(chan), err);
|
||||
- else
|
||||
- break;
|
||||
- if (--device->privatecnt == 0)
|
||||
- dma_cap_clear(DMA_PRIVATE, device->cap_mask);
|
||||
- chan = NULL;
|
||||
- }
|
||||
+ chan = NULL;
|
||||
}
|
||||
mutex_unlock(&dma_list_mutex);
|
||||
|
|
@ -1,335 +0,0 @@
|
|||
From a8135d0d79e9d0ad3a4ff494fceeaae838becf38 Mon Sep 17 00:00:00 2001
|
||||
From: Peter Ujfalusi <peter.ujfalusi@ti.com>
|
||||
Date: Mon, 14 Dec 2015 22:47:40 +0200
|
||||
Subject: [PATCH 2/3] dmaengine: core: Introduce new, universal API to request
|
||||
a channel
|
||||
|
||||
The two API function can cover most, if not all current APIs used to
|
||||
request a channel. With minimal effort dmaengine drivers, platforms and
|
||||
dmaengine user drivers can be converted to use the two function.
|
||||
|
||||
struct dma_chan *dma_request_chan_by_mask(const dma_cap_mask_t *mask);
|
||||
|
||||
To request any channel matching with the requested capabilities, can be
|
||||
used to request channel for memcpy, memset, xor, etc where no hardware
|
||||
synchronization is needed.
|
||||
|
||||
struct dma_chan *dma_request_chan(struct device *dev, const char *name);
|
||||
To request a slave channel. The dma_request_chan() will try to find the
|
||||
channel via DT, ACPI or in case if the kernel booted in non DT/ACPI mode
|
||||
it will use a filter lookup table and retrieves the needed information from
|
||||
the dma_slave_map provided by the DMA drivers.
|
||||
This legacy mode needs changes in platform code, in dmaengine drivers and
|
||||
finally the dmaengine user drivers can be converted:
|
||||
|
||||
For each dmaengine driver an array of DMA device, slave and the parameter
|
||||
for the filter function needs to be added:
|
||||
|
||||
static const struct dma_slave_map da830_edma_map[] = {
|
||||
{ "davinci-mcasp.0", "rx", EDMA_FILTER_PARAM(0, 0) },
|
||||
{ "davinci-mcasp.0", "tx", EDMA_FILTER_PARAM(0, 1) },
|
||||
{ "davinci-mcasp.1", "rx", EDMA_FILTER_PARAM(0, 2) },
|
||||
{ "davinci-mcasp.1", "tx", EDMA_FILTER_PARAM(0, 3) },
|
||||
{ "davinci-mcasp.2", "rx", EDMA_FILTER_PARAM(0, 4) },
|
||||
{ "davinci-mcasp.2", "tx", EDMA_FILTER_PARAM(0, 5) },
|
||||
{ "spi_davinci.0", "rx", EDMA_FILTER_PARAM(0, 14) },
|
||||
{ "spi_davinci.0", "tx", EDMA_FILTER_PARAM(0, 15) },
|
||||
{ "da830-mmc.0", "rx", EDMA_FILTER_PARAM(0, 16) },
|
||||
{ "da830-mmc.0", "tx", EDMA_FILTER_PARAM(0, 17) },
|
||||
{ "spi_davinci.1", "rx", EDMA_FILTER_PARAM(0, 18) },
|
||||
{ "spi_davinci.1", "tx", EDMA_FILTER_PARAM(0, 19) },
|
||||
};
|
||||
|
||||
This information is going to be needed by the dmaengine driver, so
|
||||
modification to the platform_data is needed, and the driver map should be
|
||||
added to the pdata of the DMA driver:
|
||||
|
||||
da8xx_edma0_pdata.slave_map = da830_edma_map;
|
||||
da8xx_edma0_pdata.slavecnt = ARRAY_SIZE(da830_edma_map);
|
||||
|
||||
The DMA driver then needs to configure the needed device -> filter_fn
|
||||
mapping before it registers with dma_async_device_register() :
|
||||
|
||||
ecc->dma_slave.filter_map.map = info->slave_map;
|
||||
ecc->dma_slave.filter_map.mapcnt = info->slavecnt;
|
||||
ecc->dma_slave.filter_map.fn = edma_filter_fn;
|
||||
|
||||
When neither DT or ACPI lookup is available the dma_request_chan() will
|
||||
try to match the requester's device name with the filter_map's list of
|
||||
device names, when a match found it will use the information from the
|
||||
dma_slave_map to get the channel with the dma_get_channel() internal
|
||||
function.
|
||||
|
||||
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
|
||||
Reviewed-by: Arnd Bergmann <arnd@arndb.de>
|
||||
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
|
||||
---
|
||||
Documentation/dmaengine/client.txt | 23 +++-------
|
||||
drivers/dma/dmaengine.c | 89 +++++++++++++++++++++++++++++++++-----
|
||||
include/linux/dmaengine.h | 51 +++++++++++++++++++---
|
||||
3 files changed, 127 insertions(+), 36 deletions(-)
|
||||
|
||||
--- a/Documentation/dmaengine/client.txt
|
||||
+++ b/Documentation/dmaengine/client.txt
|
||||
@@ -22,25 +22,14 @@ The slave DMA usage consists of followin
|
||||
Channel allocation is slightly different in the slave DMA context,
|
||||
client drivers typically need a channel from a particular DMA
|
||||
controller only and even in some cases a specific channel is desired.
|
||||
- To request a channel dma_request_channel() API is used.
|
||||
+ To request a channel dma_request_chan() API is used.
|
||||
|
||||
Interface:
|
||||
- struct dma_chan *dma_request_channel(dma_cap_mask_t mask,
|
||||
- dma_filter_fn filter_fn,
|
||||
- void *filter_param);
|
||||
- where dma_filter_fn is defined as:
|
||||
- typedef bool (*dma_filter_fn)(struct dma_chan *chan, void *filter_param);
|
||||
+ struct dma_chan *dma_request_chan(struct device *dev, const char *name);
|
||||
|
||||
- The 'filter_fn' parameter is optional, but highly recommended for
|
||||
- slave and cyclic channels as they typically need to obtain a specific
|
||||
- DMA channel.
|
||||
-
|
||||
- When the optional 'filter_fn' parameter is NULL, dma_request_channel()
|
||||
- simply returns the first channel that satisfies the capability mask.
|
||||
-
|
||||
- Otherwise, the 'filter_fn' routine will be called once for each free
|
||||
- channel which has a capability in 'mask'. 'filter_fn' is expected to
|
||||
- return 'true' when the desired DMA channel is found.
|
||||
+ Which will find and return the 'name' DMA channel associated with the 'dev'
|
||||
+ device. The association is done via DT, ACPI or board file based
|
||||
+ dma_slave_map matching table.
|
||||
|
||||
A channel allocated via this interface is exclusive to the caller,
|
||||
until dma_release_channel() is called.
|
||||
--- a/drivers/dma/dmaengine.c
|
||||
+++ b/drivers/dma/dmaengine.c
|
||||
@@ -43,6 +43,7 @@
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
+#include <linux/platform_device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
@@ -665,27 +666,73 @@ struct dma_chan *__dma_request_channel(c
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__dma_request_channel);
|
||||
|
||||
+static const struct dma_slave_map *dma_filter_match(struct dma_device *device,
|
||||
+ const char *name,
|
||||
+ struct device *dev)
|
||||
+{
|
||||
+ int i;
|
||||
+
|
||||
+ if (!device->filter.mapcnt)
|
||||
+ return NULL;
|
||||
+
|
||||
+ for (i = 0; i < device->filter.mapcnt; i++) {
|
||||
+ const struct dma_slave_map *map = &device->filter.map[i];
|
||||
+
|
||||
+ if (!strcmp(map->devname, dev_name(dev)) &&
|
||||
+ !strcmp(map->slave, name))
|
||||
+ return map;
|
||||
+ }
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
/**
|
||||
- * dma_request_slave_channel_reason - try to allocate an exclusive slave channel
|
||||
+ * dma_request_chan - try to allocate an exclusive slave channel
|
||||
* @dev: pointer to client device structure
|
||||
* @name: slave channel name
|
||||
*
|
||||
* Returns pointer to appropriate DMA channel on success or an error pointer.
|
||||
*/
|
||||
-struct dma_chan *dma_request_slave_channel_reason(struct device *dev,
|
||||
- const char *name)
|
||||
+struct dma_chan *dma_request_chan(struct device *dev, const char *name)
|
||||
{
|
||||
+ struct dma_device *d, *_d;
|
||||
+ struct dma_chan *chan = NULL;
|
||||
+
|
||||
/* If device-tree is present get slave info from here */
|
||||
if (dev->of_node)
|
||||
- return of_dma_request_slave_channel(dev->of_node, name);
|
||||
+ chan = of_dma_request_slave_channel(dev->of_node, name);
|
||||
|
||||
/* If device was enumerated by ACPI get slave info from here */
|
||||
- if (ACPI_HANDLE(dev))
|
||||
- return acpi_dma_request_slave_chan_by_name(dev, name);
|
||||
+ if (has_acpi_companion(dev) && !chan)
|
||||
+ chan = acpi_dma_request_slave_chan_by_name(dev, name);
|
||||
+
|
||||
+ if (chan) {
|
||||
+ /* Valid channel found or requester need to be deferred */
|
||||
+ if (!IS_ERR(chan) || PTR_ERR(chan) == -EPROBE_DEFER)
|
||||
+ return chan;
|
||||
+ }
|
||||
+
|
||||
+ /* Try to find the channel via the DMA filter map(s) */
|
||||
+ mutex_lock(&dma_list_mutex);
|
||||
+ list_for_each_entry_safe(d, _d, &dma_device_list, global_node) {
|
||||
+ dma_cap_mask_t mask;
|
||||
+ const struct dma_slave_map *map = dma_filter_match(d, name, dev);
|
||||
+
|
||||
+ if (!map)
|
||||
+ continue;
|
||||
+
|
||||
+ dma_cap_zero(mask);
|
||||
+ dma_cap_set(DMA_SLAVE, mask);
|
||||
|
||||
- return ERR_PTR(-ENODEV);
|
||||
+ chan = find_candidate(d, &mask, d->filter.fn, map->param);
|
||||
+ if (!IS_ERR(chan))
|
||||
+ break;
|
||||
+ }
|
||||
+ mutex_unlock(&dma_list_mutex);
|
||||
+
|
||||
+ return chan ? chan : ERR_PTR(-EPROBE_DEFER);
|
||||
}
|
||||
-EXPORT_SYMBOL_GPL(dma_request_slave_channel_reason);
|
||||
+EXPORT_SYMBOL_GPL(dma_request_chan);
|
||||
|
||||
/**
|
||||
* dma_request_slave_channel - try to allocate an exclusive slave channel
|
||||
@@ -697,17 +744,35 @@ EXPORT_SYMBOL_GPL(dma_request_slave_chan
|
||||
struct dma_chan *dma_request_slave_channel(struct device *dev,
|
||||
const char *name)
|
||||
{
|
||||
- struct dma_chan *ch = dma_request_slave_channel_reason(dev, name);
|
||||
+ struct dma_chan *ch = dma_request_chan(dev, name);
|
||||
if (IS_ERR(ch))
|
||||
return NULL;
|
||||
|
||||
- dma_cap_set(DMA_PRIVATE, ch->device->cap_mask);
|
||||
- ch->device->privatecnt++;
|
||||
-
|
||||
return ch;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dma_request_slave_channel);
|
||||
|
||||
+/**
|
||||
+ * dma_request_chan_by_mask - allocate a channel satisfying certain capabilities
|
||||
+ * @mask: capabilities that the channel must satisfy
|
||||
+ *
|
||||
+ * Returns pointer to appropriate DMA channel on success or an error pointer.
|
||||
+ */
|
||||
+struct dma_chan *dma_request_chan_by_mask(const dma_cap_mask_t *mask)
|
||||
+{
|
||||
+ struct dma_chan *chan;
|
||||
+
|
||||
+ if (!mask)
|
||||
+ return ERR_PTR(-ENODEV);
|
||||
+
|
||||
+ chan = __dma_request_channel(mask, NULL, NULL);
|
||||
+ if (!chan)
|
||||
+ chan = ERR_PTR(-ENODEV);
|
||||
+
|
||||
+ return chan;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(dma_request_chan_by_mask);
|
||||
+
|
||||
void dma_release_channel(struct dma_chan *chan)
|
||||
{
|
||||
mutex_lock(&dma_list_mutex);
|
||||
--- a/include/linux/dmaengine.h
|
||||
+++ b/include/linux/dmaengine.h
|
||||
@@ -607,11 +607,38 @@ enum dmaengine_alignment {
|
||||
};
|
||||
|
||||
/**
|
||||
+ * struct dma_slave_map - associates slave device and it's slave channel with
|
||||
+ * parameter to be used by a filter function
|
||||
+ * @devname: name of the device
|
||||
+ * @slave: slave channel name
|
||||
+ * @param: opaque parameter to pass to struct dma_filter.fn
|
||||
+ */
|
||||
+struct dma_slave_map {
|
||||
+ const char *devname;
|
||||
+ const char *slave;
|
||||
+ void *param;
|
||||
+};
|
||||
+
|
||||
+/**
|
||||
+ * struct dma_filter - information for slave device/channel to filter_fn/param
|
||||
+ * mapping
|
||||
+ * @fn: filter function callback
|
||||
+ * @mapcnt: number of slave device/channel in the map
|
||||
+ * @map: array of channel to filter mapping data
|
||||
+ */
|
||||
+struct dma_filter {
|
||||
+ dma_filter_fn fn;
|
||||
+ int mapcnt;
|
||||
+ const struct dma_slave_map *map;
|
||||
+};
|
||||
+
|
||||
+/**
|
||||
* struct dma_device - info on the entity supplying DMA services
|
||||
* @chancnt: how many DMA channels are supported
|
||||
* @privatecnt: how many DMA channels are requested by dma_request_channel
|
||||
* @channels: the list of struct dma_chan
|
||||
* @global_node: list_head for global dma_device_list
|
||||
+ * @filter: information for device/slave to filter function/param mapping
|
||||
* @cap_mask: one or more dma_capability flags
|
||||
* @max_xor: maximum number of xor sources, 0 if no capability
|
||||
* @max_pq: maximum number of PQ sources and PQ-continue capability
|
||||
@@ -666,6 +693,7 @@ struct dma_device {
|
||||
unsigned int privatecnt;
|
||||
struct list_head channels;
|
||||
struct list_head global_node;
|
||||
+ struct dma_filter filter;
|
||||
dma_cap_mask_t cap_mask;
|
||||
unsigned short max_xor;
|
||||
unsigned short max_pq;
|
||||
@@ -1140,9 +1168,11 @@ enum dma_status dma_wait_for_async_tx(st
|
||||
void dma_issue_pending_all(void);
|
||||
struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask,
|
||||
dma_filter_fn fn, void *fn_param);
|
||||
-struct dma_chan *dma_request_slave_channel_reason(struct device *dev,
|
||||
- const char *name);
|
||||
struct dma_chan *dma_request_slave_channel(struct device *dev, const char *name);
|
||||
+
|
||||
+struct dma_chan *dma_request_chan(struct device *dev, const char *name);
|
||||
+struct dma_chan *dma_request_chan_by_mask(const dma_cap_mask_t *mask);
|
||||
+
|
||||
void dma_release_channel(struct dma_chan *chan);
|
||||
int dma_get_slave_caps(struct dma_chan *chan, struct dma_slave_caps *caps);
|
||||
#else
|
||||
@@ -1166,16 +1196,21 @@ static inline struct dma_chan *__dma_req
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
-static inline struct dma_chan *dma_request_slave_channel_reason(
|
||||
- struct device *dev, const char *name)
|
||||
-{
|
||||
- return ERR_PTR(-ENODEV);
|
||||
-}
|
||||
static inline struct dma_chan *dma_request_slave_channel(struct device *dev,
|
||||
const char *name)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
+static inline struct dma_chan *dma_request_chan(struct device *dev,
|
||||
+ const char *name)
|
||||
+{
|
||||
+ return ERR_PTR(-ENODEV);
|
||||
+}
|
||||
+static inline struct dma_chan *dma_request_chan_by_mask(
|
||||
+ const dma_cap_mask_t *mask)
|
||||
+{
|
||||
+ return ERR_PTR(-ENODEV);
|
||||
+}
|
||||
static inline void dma_release_channel(struct dma_chan *chan)
|
||||
{
|
||||
}
|
||||
@@ -1186,6 +1221,8 @@ static inline int dma_get_slave_caps(str
|
||||
}
|
||||
#endif
|
||||
|
||||
+#define dma_request_slave_channel_reason(dev, name) dma_request_chan(dev, name)
|
||||
+
|
||||
static inline int dmaengine_desc_set_reuse(struct dma_async_tx_descriptor *tx)
|
||||
{
|
||||
struct dma_slave_caps caps;
|
|
@ -1,282 +0,0 @@
|
|||
From b36f09c3c441a6e59eab9315032e7d546571de3f Mon Sep 17 00:00:00 2001
|
||||
From: Lars-Peter Clausen <lars@metafoo.de>
|
||||
Date: Tue, 20 Oct 2015 11:46:28 +0200
|
||||
Subject: [PATCH] dmaengine: Add transfer termination synchronization support
|
||||
|
||||
The DMAengine API has a long standing race condition that is inherent to
|
||||
the API itself. Calling dmaengine_terminate_all() is supposed to stop and
|
||||
abort any pending or active transfers that have previously been submitted.
|
||||
Unfortunately it is possible that this operation races against a currently
|
||||
running (or with some drivers also scheduled) completion callback.
|
||||
|
||||
Since the API allows dmaengine_terminate_all() to be called from atomic
|
||||
context as well as from within a completion callback it is not possible to
|
||||
synchronize to the execution of the completion callback from within
|
||||
dmaengine_terminate_all() itself.
|
||||
|
||||
This means that a user of the DMAengine API does not know when it is safe
|
||||
to free resources used in the completion callback, which can result in a
|
||||
use-after-free race condition.
|
||||
|
||||
This patch addresses the issue by introducing an explicit synchronization
|
||||
primitive to the DMAengine API called dmaengine_synchronize().
|
||||
|
||||
The existing dmaengine_terminate_all() is deprecated in favor of
|
||||
dmaengine_terminate_sync() and dmaengine_terminate_async(). The former
|
||||
aborts all pending and active transfers and synchronizes to the current
|
||||
context, meaning it will wait until all running completion callbacks have
|
||||
finished. This means it is only possible to call this function from
|
||||
non-atomic context. The later function does not synchronize, but can still
|
||||
be used in atomic context or from within a complete callback. It has to be
|
||||
followed up by dmaengine_synchronize() before a client can free the
|
||||
resources used in a completion callback.
|
||||
|
||||
In addition to this the semantics of the device_terminate_all() callback
|
||||
are slightly relaxed by this patch. It is now OK for a driver to only
|
||||
schedule the termination of the active transfer, but does not necessarily
|
||||
have to wait until the DMA controller has completely stopped. The driver
|
||||
must ensure though that the controller has stopped and no longer accesses
|
||||
any memory when the device_synchronize() callback returns.
|
||||
|
||||
This was in part done since most drivers do not pay attention to this
|
||||
anyway at the moment and to emphasize that this needs to be done when the
|
||||
device_synchronize() callback is implemented. But it also helps with
|
||||
implementing support for devices where stopping the controller can require
|
||||
operations that may sleep.
|
||||
|
||||
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
|
||||
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
|
||||
---
|
||||
Documentation/dmaengine/client.txt | 38 ++++++++++++++-
|
||||
Documentation/dmaengine/provider.txt | 20 +++++++-
|
||||
drivers/dma/dmaengine.c | 5 +-
|
||||
include/linux/dmaengine.h | 90 ++++++++++++++++++++++++++++++++++++
|
||||
4 files changed, 148 insertions(+), 5 deletions(-)
|
||||
|
||||
--- a/Documentation/dmaengine/client.txt
|
||||
+++ b/Documentation/dmaengine/client.txt
|
||||
@@ -117,7 +117,7 @@ The slave DMA usage consists of followin
|
||||
transaction.
|
||||
|
||||
For cyclic DMA, a callback function may wish to terminate the
|
||||
- DMA via dmaengine_terminate_all().
|
||||
+ DMA via dmaengine_terminate_async().
|
||||
|
||||
Therefore, it is important that DMA engine drivers drop any
|
||||
locks before calling the callback function which may cause a
|
||||
@@ -155,12 +155,29 @@ The slave DMA usage consists of followin
|
||||
|
||||
Further APIs:
|
||||
|
||||
-1. int dmaengine_terminate_all(struct dma_chan *chan)
|
||||
+1. int dmaengine_terminate_sync(struct dma_chan *chan)
|
||||
+ int dmaengine_terminate_async(struct dma_chan *chan)
|
||||
+ int dmaengine_terminate_all(struct dma_chan *chan) /* DEPRECATED */
|
||||
|
||||
This causes all activity for the DMA channel to be stopped, and may
|
||||
discard data in the DMA FIFO which hasn't been fully transferred.
|
||||
No callback functions will be called for any incomplete transfers.
|
||||
|
||||
+ Two variants of this function are available.
|
||||
+
|
||||
+ dmaengine_terminate_async() might not wait until the DMA has been fully
|
||||
+ stopped or until any running complete callbacks have finished. But it is
|
||||
+ possible to call dmaengine_terminate_async() from atomic context or from
|
||||
+ within a complete callback. dmaengine_synchronize() must be called before it
|
||||
+ is safe to free the memory accessed by the DMA transfer or free resources
|
||||
+ accessed from within the complete callback.
|
||||
+
|
||||
+ dmaengine_terminate_sync() will wait for the transfer and any running
|
||||
+ complete callbacks to finish before it returns. But the function must not be
|
||||
+ called from atomic context or from within a complete callback.
|
||||
+
|
||||
+ dmaengine_terminate_all() is deprecated and should not be used in new code.
|
||||
+
|
||||
2. int dmaengine_pause(struct dma_chan *chan)
|
||||
|
||||
This pauses activity on the DMA channel without data loss.
|
||||
@@ -186,3 +203,20 @@ Further APIs:
|
||||
a running DMA channel. It is recommended that DMA engine users
|
||||
pause or stop (via dmaengine_terminate_all()) the channel before
|
||||
using this API.
|
||||
+
|
||||
+5. void dmaengine_synchronize(struct dma_chan *chan)
|
||||
+
|
||||
+ Synchronize the termination of the DMA channel to the current context.
|
||||
+
|
||||
+ This function should be used after dmaengine_terminate_async() to synchronize
|
||||
+ the termination of the DMA channel to the current context. The function will
|
||||
+ wait for the transfer and any running complete callbacks to finish before it
|
||||
+ returns.
|
||||
+
|
||||
+ If dmaengine_terminate_async() is used to stop the DMA channel this function
|
||||
+ must be called before it is safe to free memory accessed by previously
|
||||
+ submitted descriptors or to free any resources accessed within the complete
|
||||
+ callback of previously submitted descriptors.
|
||||
+
|
||||
+ The behavior of this function is undefined if dma_async_issue_pending() has
|
||||
+ been called between dmaengine_terminate_async() and this function.
|
||||
--- a/Documentation/dmaengine/provider.txt
|
||||
+++ b/Documentation/dmaengine/provider.txt
|
||||
@@ -327,8 +327,24 @@ supported.
|
||||
|
||||
* device_terminate_all
|
||||
- Aborts all the pending and ongoing transfers on the channel
|
||||
- - This command should operate synchronously on the channel,
|
||||
- terminating right away all the channels
|
||||
+ - For aborted transfers the complete callback should not be called
|
||||
+ - Can be called from atomic context or from within a complete
|
||||
+ callback of a descriptor. Must not sleep. Drivers must be able
|
||||
+ to handle this correctly.
|
||||
+ - Termination may be asynchronous. The driver does not have to
|
||||
+ wait until the currently active transfer has completely stopped.
|
||||
+ See device_synchronize.
|
||||
+
|
||||
+ * device_synchronize
|
||||
+ - Must synchronize the termination of a channel to the current
|
||||
+ context.
|
||||
+ - Must make sure that memory for previously submitted
|
||||
+ descriptors is no longer accessed by the DMA controller.
|
||||
+ - Must make sure that all complete callbacks for previously
|
||||
+ submitted descriptors have finished running and none are
|
||||
+ scheduled to run.
|
||||
+ - May sleep.
|
||||
+
|
||||
|
||||
Misc notes (stuff that should be documented, but don't really know
|
||||
where to put them)
|
||||
--- a/drivers/dma/dmaengine.c
|
||||
+++ b/drivers/dma/dmaengine.c
|
||||
@@ -266,8 +266,11 @@ static void dma_chan_put(struct dma_chan
|
||||
module_put(dma_chan_to_owner(chan));
|
||||
|
||||
/* This channel is not in use anymore, free it */
|
||||
- if (!chan->client_count && chan->device->device_free_chan_resources)
|
||||
+ if (!chan->client_count && chan->device->device_free_chan_resources) {
|
||||
+ /* Make sure all operations have completed */
|
||||
+ dmaengine_synchronize(chan);
|
||||
chan->device->device_free_chan_resources(chan);
|
||||
+ }
|
||||
|
||||
/* If the channel is used via a DMA request router, free the mapping */
|
||||
if (chan->router && chan->router->route_free) {
|
||||
--- a/include/linux/dmaengine.h
|
||||
+++ b/include/linux/dmaengine.h
|
||||
@@ -681,6 +681,8 @@ struct dma_filter {
|
||||
* paused. Returns 0 or an error code
|
||||
* @device_terminate_all: Aborts all transfers on a channel. Returns 0
|
||||
* or an error code
|
||||
+ * @device_synchronize: Synchronizes the termination of a transfers to the
|
||||
+ * current context.
|
||||
* @device_tx_status: poll for transaction completion, the optional
|
||||
* txstate parameter can be supplied with a pointer to get a
|
||||
* struct with auxiliary transfer status information, otherwise the call
|
||||
@@ -765,6 +767,7 @@ struct dma_device {
|
||||
int (*device_pause)(struct dma_chan *chan);
|
||||
int (*device_resume)(struct dma_chan *chan);
|
||||
int (*device_terminate_all)(struct dma_chan *chan);
|
||||
+ void (*device_synchronize)(struct dma_chan *chan);
|
||||
|
||||
enum dma_status (*device_tx_status)(struct dma_chan *chan,
|
||||
dma_cookie_t cookie,
|
||||
@@ -856,6 +859,13 @@ static inline struct dma_async_tx_descri
|
||||
src_sg, src_nents, flags);
|
||||
}
|
||||
|
||||
+/**
|
||||
+ * dmaengine_terminate_all() - Terminate all active DMA transfers
|
||||
+ * @chan: The channel for which to terminate the transfers
|
||||
+ *
|
||||
+ * This function is DEPRECATED use either dmaengine_terminate_sync() or
|
||||
+ * dmaengine_terminate_async() instead.
|
||||
+ */
|
||||
static inline int dmaengine_terminate_all(struct dma_chan *chan)
|
||||
{
|
||||
if (chan->device->device_terminate_all)
|
||||
@@ -864,6 +874,86 @@ static inline int dmaengine_terminate_al
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
+/**
|
||||
+ * dmaengine_terminate_async() - Terminate all active DMA transfers
|
||||
+ * @chan: The channel for which to terminate the transfers
|
||||
+ *
|
||||
+ * Calling this function will terminate all active and pending descriptors
|
||||
+ * that have previously been submitted to the channel. It is not guaranteed
|
||||
+ * though that the transfer for the active descriptor has stopped when the
|
||||
+ * function returns. Furthermore it is possible the complete callback of a
|
||||
+ * submitted transfer is still running when this function returns.
|
||||
+ *
|
||||
+ * dmaengine_synchronize() needs to be called before it is safe to free
|
||||
+ * any memory that is accessed by previously submitted descriptors or before
|
||||
+ * freeing any resources accessed from within the completion callback of any
|
||||
+ * perviously submitted descriptors.
|
||||
+ *
|
||||
+ * This function can be called from atomic context as well as from within a
|
||||
+ * complete callback of a descriptor submitted on the same channel.
|
||||
+ *
|
||||
+ * If none of the two conditions above apply consider using
|
||||
+ * dmaengine_terminate_sync() instead.
|
||||
+ */
|
||||
+static inline int dmaengine_terminate_async(struct dma_chan *chan)
|
||||
+{
|
||||
+ if (chan->device->device_terminate_all)
|
||||
+ return chan->device->device_terminate_all(chan);
|
||||
+
|
||||
+ return -EINVAL;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * dmaengine_synchronize() - Synchronize DMA channel termination
|
||||
+ * @chan: The channel to synchronize
|
||||
+ *
|
||||
+ * Synchronizes to the DMA channel termination to the current context. When this
|
||||
+ * function returns it is guaranteed that all transfers for previously issued
|
||||
+ * descriptors have stopped and and it is safe to free the memory assoicated
|
||||
+ * with them. Furthermore it is guaranteed that all complete callback functions
|
||||
+ * for a previously submitted descriptor have finished running and it is safe to
|
||||
+ * free resources accessed from within the complete callbacks.
|
||||
+ *
|
||||
+ * The behavior of this function is undefined if dma_async_issue_pending() has
|
||||
+ * been called between dmaengine_terminate_async() and this function.
|
||||
+ *
|
||||
+ * This function must only be called from non-atomic context and must not be
|
||||
+ * called from within a complete callback of a descriptor submitted on the same
|
||||
+ * channel.
|
||||
+ */
|
||||
+static inline void dmaengine_synchronize(struct dma_chan *chan)
|
||||
+{
|
||||
+ if (chan->device->device_synchronize)
|
||||
+ chan->device->device_synchronize(chan);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * dmaengine_terminate_sync() - Terminate all active DMA transfers
|
||||
+ * @chan: The channel for which to terminate the transfers
|
||||
+ *
|
||||
+ * Calling this function will terminate all active and pending transfers
|
||||
+ * that have previously been submitted to the channel. It is similar to
|
||||
+ * dmaengine_terminate_async() but guarantees that the DMA transfer has actually
|
||||
+ * stopped and that all complete callbacks have finished running when the
|
||||
+ * function returns.
|
||||
+ *
|
||||
+ * This function must only be called from non-atomic context and must not be
|
||||
+ * called from within a complete callback of a descriptor submitted on the same
|
||||
+ * channel.
|
||||
+ */
|
||||
+static inline int dmaengine_terminate_sync(struct dma_chan *chan)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = dmaengine_terminate_async(chan);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ dmaengine_synchronize(chan);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static inline int dmaengine_pause(struct dma_chan *chan)
|
||||
{
|
||||
if (chan->device->device_pause)
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,209 +0,0 @@
|
|||
From eb25cb9956cc9384b7fa0d75dec908c9fac8c444 Mon Sep 17 00:00:00 2001
|
||||
From: Stephan Linz <linz@li-pro.net>
|
||||
Date: Fri, 10 Jun 2016 07:59:56 +0200
|
||||
Subject: [PATCH] leds: convert IDE trigger to common disk trigger
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
This patch converts the IDE specific LED trigger to a generic disk
|
||||
activity LED trigger. The libata core is now a trigger source just
|
||||
like before the IDE disk driver. It's merely a replacement of the
|
||||
string ide by disk.
|
||||
|
||||
The patch is taken from http://dev.gentoo.org/~josejx/ata.patch and is
|
||||
widely used by any ibook/powerbook owners with great satisfaction.
|
||||
Likewise, it is very often used successfully on different ARM platforms.
|
||||
|
||||
Unlike the original patch, the existing 'ide-disk' trigger is still
|
||||
available for backward compatibility. That reduce the amount of patches
|
||||
in affected device trees out of the mainline kernel. For further
|
||||
development, the new name 'disk-activity' should be used.
|
||||
|
||||
Cc: Joseph Jezak <josejx@gentoo.org>
|
||||
Cc: Jörg Sommer <joerg@alea.gnuu.de>
|
||||
Cc: Richard Purdie <rpurdie@rpsys.net>
|
||||
Signed-off-by: Stephan Linz <linz@li-pro.net>
|
||||
Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
|
||||
---
|
||||
drivers/ata/libata-core.c | 4 ++++
|
||||
drivers/ide/ide-disk.c | 2 +-
|
||||
drivers/leds/trigger/Kconfig | 8 +++----
|
||||
drivers/leds/trigger/Makefile | 2 +-
|
||||
drivers/leds/trigger/ledtrig-disk.c | 41 +++++++++++++++++++++++++++++++++
|
||||
drivers/leds/trigger/ledtrig-ide-disk.c | 36 -----------------------------
|
||||
include/linux/leds.h | 6 ++---
|
||||
8 files changed, 55 insertions(+), 46 deletions(-)
|
||||
create mode 100644 drivers/leds/trigger/ledtrig-disk.c
|
||||
delete mode 100644 drivers/leds/trigger/ledtrig-ide-disk.c
|
||||
|
||||
--- a/drivers/ata/libata-core.c
|
||||
+++ b/drivers/ata/libata-core.c
|
||||
@@ -67,6 +67,7 @@
|
||||
#include <asm/byteorder.h>
|
||||
#include <linux/cdrom.h>
|
||||
#include <linux/ratelimit.h>
|
||||
+#include <linux/leds.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
@@ -4914,6 +4915,9 @@ void ata_qc_complete(struct ata_queued_c
|
||||
{
|
||||
struct ata_port *ap = qc->ap;
|
||||
|
||||
+ /* Trigger the LED (if available) */
|
||||
+ ledtrig_disk_activity();
|
||||
+
|
||||
/* XXX: New EH and old EH use different mechanisms to
|
||||
* synchronize EH with regular execution path.
|
||||
*
|
||||
--- a/drivers/ide/ide-disk.c
|
||||
+++ b/drivers/ide/ide-disk.c
|
||||
@@ -186,7 +186,7 @@ static ide_startstop_t ide_do_rw_disk(id
|
||||
BUG_ON(drive->dev_flags & IDE_DFLAG_BLOCKED);
|
||||
BUG_ON(rq->cmd_type != REQ_TYPE_FS);
|
||||
|
||||
- ledtrig_ide_activity();
|
||||
+ ledtrig_disk_activity();
|
||||
|
||||
pr_debug("%s: %sing: block=%llu, sectors=%u\n",
|
||||
drive->name, rq_data_dir(rq) == READ ? "read" : "writ",
|
||||
--- a/drivers/leds/trigger/Kconfig
|
||||
+++ b/drivers/leds/trigger/Kconfig
|
||||
@@ -33,12 +33,12 @@ config LEDS_TRIGGER_ONESHOT
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
-config LEDS_TRIGGER_IDE_DISK
|
||||
- bool "LED IDE Disk Trigger"
|
||||
- depends on IDE_GD_ATA
|
||||
+config LEDS_TRIGGER_DISK
|
||||
+ bool "LED Disk Trigger"
|
||||
+ depends on IDE_GD_ATA || ATA
|
||||
depends on LEDS_TRIGGERS
|
||||
help
|
||||
- This allows LEDs to be controlled by IDE disk activity.
|
||||
+ This allows LEDs to be controlled by disk activity.
|
||||
If unsure, say Y.
|
||||
|
||||
config LEDS_TRIGGER_HEARTBEAT
|
||||
--- a/drivers/leds/trigger/Makefile
|
||||
+++ b/drivers/leds/trigger/Makefile
|
||||
@@ -1,6 +1,6 @@
|
||||
obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o
|
||||
obj-$(CONFIG_LEDS_TRIGGER_ONESHOT) += ledtrig-oneshot.o
|
||||
-obj-$(CONFIG_LEDS_TRIGGER_IDE_DISK) += ledtrig-ide-disk.o
|
||||
+obj-$(CONFIG_LEDS_TRIGGER_DISK) += ledtrig-disk.o
|
||||
obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT) += ledtrig-heartbeat.o
|
||||
obj-$(CONFIG_LEDS_TRIGGER_BACKLIGHT) += ledtrig-backlight.o
|
||||
obj-$(CONFIG_LEDS_TRIGGER_GPIO) += ledtrig-gpio.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/leds/trigger/ledtrig-disk.c
|
||||
@@ -0,0 +1,41 @@
|
||||
+/*
|
||||
+ * LED Disk Activity Trigger
|
||||
+ *
|
||||
+ * Copyright 2006 Openedhand Ltd.
|
||||
+ *
|
||||
+ * Author: Richard Purdie <rpurdie@openedhand.com>
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify
|
||||
+ * it under the terms of the GNU General Public License version 2 as
|
||||
+ * published by the Free Software Foundation.
|
||||
+ *
|
||||
+ */
|
||||
+
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/init.h>
|
||||
+#include <linux/leds.h>
|
||||
+
|
||||
+#define BLINK_DELAY 30
|
||||
+
|
||||
+DEFINE_LED_TRIGGER(ledtrig_disk);
|
||||
+DEFINE_LED_TRIGGER(ledtrig_ide);
|
||||
+
|
||||
+void ledtrig_disk_activity(void)
|
||||
+{
|
||||
+ unsigned long blink_delay = BLINK_DELAY;
|
||||
+
|
||||
+ led_trigger_blink_oneshot(ledtrig_disk,
|
||||
+ &blink_delay, &blink_delay, 0);
|
||||
+ led_trigger_blink_oneshot(ledtrig_ide,
|
||||
+ &blink_delay, &blink_delay, 0);
|
||||
+}
|
||||
+EXPORT_SYMBOL(ledtrig_disk_activity);
|
||||
+
|
||||
+static int __init ledtrig_disk_init(void)
|
||||
+{
|
||||
+ led_trigger_register_simple("disk-activity", &ledtrig_disk);
|
||||
+ led_trigger_register_simple("ide-disk", &ledtrig_ide);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+device_initcall(ledtrig_disk_init);
|
||||
--- a/drivers/leds/trigger/ledtrig-ide-disk.c
|
||||
+++ /dev/null
|
||||
@@ -1,47 +0,0 @@
|
||||
-/*
|
||||
- * LED IDE-Disk Activity Trigger
|
||||
- *
|
||||
- * Copyright 2006 Openedhand Ltd.
|
||||
- *
|
||||
- * Author: Richard Purdie <rpurdie@openedhand.com>
|
||||
- *
|
||||
- * This program is free software; you can redistribute it and/or modify
|
||||
- * it under the terms of the GNU General Public License version 2 as
|
||||
- * published by the Free Software Foundation.
|
||||
- *
|
||||
- */
|
||||
-
|
||||
-#include <linux/module.h>
|
||||
-#include <linux/kernel.h>
|
||||
-#include <linux/init.h>
|
||||
-#include <linux/leds.h>
|
||||
-
|
||||
-#define BLINK_DELAY 30
|
||||
-
|
||||
-DEFINE_LED_TRIGGER(ledtrig_ide);
|
||||
-static unsigned long ide_blink_delay = BLINK_DELAY;
|
||||
-
|
||||
-void ledtrig_ide_activity(void)
|
||||
-{
|
||||
- led_trigger_blink_oneshot(ledtrig_ide,
|
||||
- &ide_blink_delay, &ide_blink_delay, 0);
|
||||
-}
|
||||
-EXPORT_SYMBOL(ledtrig_ide_activity);
|
||||
-
|
||||
-static int __init ledtrig_ide_init(void)
|
||||
-{
|
||||
- led_trigger_register_simple("ide-disk", &ledtrig_ide);
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
-static void __exit ledtrig_ide_exit(void)
|
||||
-{
|
||||
- led_trigger_unregister_simple(ledtrig_ide);
|
||||
-}
|
||||
-
|
||||
-module_init(ledtrig_ide_init);
|
||||
-module_exit(ledtrig_ide_exit);
|
||||
-
|
||||
-MODULE_AUTHOR("Richard Purdie <rpurdie@openedhand.com>");
|
||||
-MODULE_DESCRIPTION("LED IDE Disk Activity Trigger");
|
||||
-MODULE_LICENSE("GPL");
|
||||
--- a/include/linux/leds.h
|
||||
+++ b/include/linux/leds.h
|
||||
@@ -308,10 +308,10 @@ static inline void *led_get_trigger_data
|
||||
#endif /* CONFIG_LEDS_TRIGGERS */
|
||||
|
||||
/* Trigger specific functions */
|
||||
-#ifdef CONFIG_LEDS_TRIGGER_IDE_DISK
|
||||
-extern void ledtrig_ide_activity(void);
|
||||
+#ifdef CONFIG_LEDS_TRIGGER_DISK
|
||||
+extern void ledtrig_disk_activity(void);
|
||||
#else
|
||||
-static inline void ledtrig_ide_activity(void) {}
|
||||
+static inline void ledtrig_disk_activity(void) {}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_LEDS_TRIGGER_CAMERA) || defined(CONFIG_LEDS_TRIGGER_CAMERA_MODULE)
|
|
@ -1,32 +0,0 @@
|
|||
--- a/arch/powerpc/platforms/44x/Kconfig
|
||||
+++ b/arch/powerpc/platforms/44x/Kconfig
|
||||
@@ -40,6 +40,19 @@ config EBONY
|
||||
help
|
||||
This option enables support for the IBM PPC440GP evaluation board.
|
||||
|
||||
+config IKAREM
|
||||
+ bool "Ikarem"
|
||||
+ depends on 44x
|
||||
+ default n
|
||||
+ select PPC44x_SIMPLE
|
||||
+ select APM821xx
|
||||
+ select PCI_MSI
|
||||
+ select PPC4xx_MSI
|
||||
+ select PPC4xx_PCI_EXPRESS
|
||||
+ select IBM_EMAC_RGMII
|
||||
+ help
|
||||
+ This option enables support for the Cisco Meraki MR24 (Ikarem) Access Point.
|
||||
+
|
||||
config SAM440EP
|
||||
bool "Sam440ep"
|
||||
depends on 44x
|
||||
--- a/arch/powerpc/platforms/44x/ppc44x_simple.c
|
||||
+++ b/arch/powerpc/platforms/44x/ppc44x_simple.c
|
||||
@@ -62,6 +62,7 @@ static char *board[] __initdata = {
|
||||
"amcc,sequoia",
|
||||
"amcc,taishan",
|
||||
"amcc,yosemite",
|
||||
+ "meraki,ikarem",
|
||||
"mosaixtech,icon"
|
||||
};
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
--- a/arch/powerpc/platforms/44x/Kconfig
|
||||
+++ b/arch/powerpc/platforms/44x/Kconfig
|
||||
@@ -143,6 +143,17 @@ config CANYONLANDS
|
||||
help
|
||||
This option enables support for the AMCC PPC460EX evaluation board.
|
||||
|
||||
+config APOLLO3G
|
||||
+ bool "Apollo3G"
|
||||
+ depends on 44x
|
||||
+ default n
|
||||
+ select PPC44x_SIMPLE
|
||||
+ select APM821xx
|
||||
+ select IBM_EMAC_RGMII
|
||||
+ select 460EX
|
||||
+ help
|
||||
+ This option enables support for the AMCC Apollo 3G board.
|
||||
+
|
||||
config GLACIER
|
||||
bool "Glacier"
|
||||
depends on 44x
|
||||
--- a/arch/powerpc/platforms/44x/ppc44x_simple.c
|
||||
+++ b/arch/powerpc/platforms/44x/ppc44x_simple.c
|
||||
@@ -50,6 +50,7 @@ machine_device_initcall(ppc44x_simple, p
|
||||
* board.c file for it rather than adding it to this list.
|
||||
*/
|
||||
static char *board[] __initdata = {
|
||||
+ "amcc,apollo3g",
|
||||
"amcc,arches",
|
||||
"amcc,bamboo",
|
||||
"apm,bluestone",
|
|
@ -1,32 +0,0 @@
|
|||
--- a/arch/powerpc/platforms/44x/Makefile
|
||||
+++ b/arch/powerpc/platforms/44x/Makefile
|
||||
@@ -3,6 +3,7 @@ ifneq ($(CONFIG_PPC4xx_CPM),y)
|
||||
obj-$(CONFIG_44x) += idle.o
|
||||
endif
|
||||
obj-$(CONFIG_PPC44x_SIMPLE) += ppc44x_simple.o
|
||||
+obj-$(CONFIG_WNDR4700) += wndr4700.o
|
||||
obj-$(CONFIG_EBONY) += ebony.o
|
||||
obj-$(CONFIG_SAM440EP) += sam440ep.o
|
||||
obj-$(CONFIG_WARP) += warp.o
|
||||
--- a/arch/powerpc/platforms/44x/Kconfig
|
||||
+++ b/arch/powerpc/platforms/44x/Kconfig
|
||||
@@ -260,6 +260,19 @@ config ICON
|
||||
help
|
||||
This option enables support for the AMCC PPC440SPe evaluation board.
|
||||
|
||||
+config WNDR4700
|
||||
+ bool "WNDR4700"
|
||||
+ depends on 44x
|
||||
+ default n
|
||||
+ select APM821xx
|
||||
+ select PCI_MSI
|
||||
+ select PPC4xx_MSI
|
||||
+ select PPC4xx_PCI_EXPRESS
|
||||
+ select IBM_EMAC_RGMII
|
||||
+ select 460EX
|
||||
+ help
|
||||
+ This option enables support for the Netgear WNDR4700/WNDR4720 board.
|
||||
+
|
||||
config XILINX_VIRTEX440_GENERIC_BOARD
|
||||
bool "Generic Xilinx Virtex 5 FXT board support"
|
||||
depends on 44x
|
|
@ -1,32 +0,0 @@
|
|||
--- a/arch/powerpc/platforms/44x/Kconfig
|
||||
+++ b/arch/powerpc/platforms/44x/Kconfig
|
||||
@@ -30,6 +30,19 @@ config BLUESTONE
|
||||
help
|
||||
This option enables support for the APM APM821xx Evaluation board.
|
||||
|
||||
+config BUCKMINSTER
|
||||
+ bool "Buckminster"
|
||||
+ depends on 44x
|
||||
+ default n
|
||||
+ select APM821xx
|
||||
+ select PCI_MSI
|
||||
+ select PPC4xx_MSI
|
||||
+ select PPC4xx_PCI_EXPRESS
|
||||
+ select IBM_EMAC_RGMII
|
||||
+ select 460EX
|
||||
+ help
|
||||
+ This option enables support for the Cisco Meraki MX60/MX60W (Buckminster) Security Appliance
|
||||
+
|
||||
config EBONY
|
||||
bool "Ebony"
|
||||
depends on 44x
|
||||
--- a/arch/powerpc/platforms/44x/ppc44x_simple.c
|
||||
+++ b/arch/powerpc/platforms/44x/ppc44x_simple.c
|
||||
@@ -63,6 +63,7 @@ static char *board[] __initdata = {
|
||||
"amcc,sequoia",
|
||||
"amcc,taishan",
|
||||
"amcc,yosemite",
|
||||
+ "meraki,buckminster",
|
||||
"meraki,ikarem",
|
||||
"mosaixtech,icon"
|
||||
};
|
|
@ -1,51 +0,0 @@
|
|||
--- a/arch/powerpc/sysdev/ppc4xx_pci.c
|
||||
+++ b/arch/powerpc/sysdev/ppc4xx_pci.c
|
||||
@@ -1066,15 +1066,24 @@ static int __init apm821xx_pciex_init_po
|
||||
u32 val;
|
||||
|
||||
/*
|
||||
- * Do a software reset on PCIe ports.
|
||||
- * This code is to fix the issue that pci drivers doesn't re-assign
|
||||
- * bus number for PCIE devices after Uboot
|
||||
- * scanned and configured all the buses (eg. PCIE NIC IntelPro/1000
|
||||
- * PT quad port, SAS LSI 1064E)
|
||||
+ * Only reset the PHY when no link is currently established.
|
||||
+ * This is for the Atheros PCIe board which has problems to establish
|
||||
+ * the link (again) after this PHY reset. All other currently tested
|
||||
+ * PCIe boards don't show this problem.
|
||||
*/
|
||||
-
|
||||
- mtdcri(SDR0, PESDR0_460EX_PHY_CTL_RST, 0x0);
|
||||
- mdelay(10);
|
||||
+ val = mfdcri(SDR0, port->sdr_base + PESDRn_LOOP);
|
||||
+ if (!(val & 0x00001000)) {
|
||||
+ /*
|
||||
+ * Do a software reset on PCIe ports.
|
||||
+ * This code is to fix the issue that pci drivers doesn't re-assign
|
||||
+ * bus number for PCIE devices after Uboot
|
||||
+ * scanned and configured all the buses (eg. PCIE NIC IntelPro/1000
|
||||
+ * PT quad port, SAS LSI 1064E)
|
||||
+ */
|
||||
+
|
||||
+ mtdcri(SDR0, PESDR0_460EX_PHY_CTL_RST, 0x0);
|
||||
+ mdelay(10);
|
||||
+ }
|
||||
|
||||
if (port->endpoint)
|
||||
val = PTYPE_LEGACY_ENDPOINT << 20;
|
||||
@@ -1091,9 +1100,12 @@ static int __init apm821xx_pciex_init_po
|
||||
mtdcri(SDR0, PESDR0_460EX_L0DRV, 0x00000130);
|
||||
mtdcri(SDR0, PESDR0_460EX_L0CLK, 0x00000006);
|
||||
|
||||
- mtdcri(SDR0, PESDR0_460EX_PHY_CTL_RST, 0x10000000);
|
||||
- mdelay(50);
|
||||
- mtdcri(SDR0, PESDR0_460EX_PHY_CTL_RST, 0x30000000);
|
||||
+ val = mfdcri(SDR0, port->sdr_base + PESDRn_LOOP);
|
||||
+ if (!(val & 0x00001000)) {
|
||||
+ mtdcri(SDR0, PESDR0_460EX_PHY_CTL_RST, 0x10000000);
|
||||
+ mdelay(50);
|
||||
+ mtdcri(SDR0, PESDR0_460EX_PHY_CTL_RST, 0x30000000);
|
||||
+ }
|
||||
|
||||
mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET,
|
||||
mfdcri(SDR0, port->sdr_base + PESDRn_RCSSET) |
|
|
@ -1,14 +0,0 @@
|
|||
--- a/arch/powerpc/sysdev/ppc4xx_pci.c
|
||||
+++ b/arch/powerpc/sysdev/ppc4xx_pci.c
|
||||
@@ -1913,9 +1913,9 @@ static void __init ppc4xx_configure_pcie
|
||||
* if it works
|
||||
*/
|
||||
out_le32(mbase + PECFG_PIM0LAL, 0x00000000);
|
||||
- out_le32(mbase + PECFG_PIM0LAH, 0x00000000);
|
||||
+ out_le32(mbase + PECFG_PIM0LAH, 0x00000008);
|
||||
out_le32(mbase + PECFG_PIM1LAL, 0x00000000);
|
||||
- out_le32(mbase + PECFG_PIM1LAH, 0x00000000);
|
||||
+ out_le32(mbase + PECFG_PIM1LAH, 0x0000000c);
|
||||
out_le32(mbase + PECFG_PIM01SAH, 0xffff0000);
|
||||
out_le32(mbase + PECFG_PIM01SAL, 0x00000000);
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
--- a/drivers/net/ethernet/ibm/emac/core.c
|
||||
+++ b/drivers/net/ethernet/ibm/emac/core.c
|
||||
@@ -129,6 +129,7 @@ static inline void emac_report_timeout_e
|
||||
{
|
||||
if (emac_has_feature(dev, EMAC_FTR_440GX_PHY_CLK_FIX |
|
||||
EMAC_FTR_460EX_PHY_CLK_FIX |
|
||||
+ EMAC_FTR_APM821XX_PHY_CLK_FIX |
|
||||
EMAC_FTR_440EP_PHY_CLK_FIX))
|
||||
DBG(dev, "%s" NL, error);
|
||||
else if (net_ratelimit())
|
||||
@@ -146,6 +147,10 @@ static inline void emac_rx_clk_tx(struct
|
||||
if (emac_has_feature(dev, EMAC_FTR_440EP_PHY_CLK_FIX))
|
||||
dcri_clrset(SDR0, SDR0_MFR,
|
||||
0, SDR0_MFR_ECS >> dev->cell_index);
|
||||
+
|
||||
+ if (emac_has_feature(dev, EMAC_FTR_APM821XX_PHY_CLK_FIX))
|
||||
+ dcri_clrset(SDR0, SDR0_ETH_CFG,
|
||||
+ 0, 0x00000100 >> dev->cell_index);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -155,6 +160,10 @@ static inline void emac_rx_clk_default(s
|
||||
if (emac_has_feature(dev, EMAC_FTR_440EP_PHY_CLK_FIX))
|
||||
dcri_clrset(SDR0, SDR0_MFR,
|
||||
SDR0_MFR_ECS >> dev->cell_index, 0);
|
||||
+
|
||||
+ if (emac_has_feature(dev, EMAC_FTR_APM821XX_PHY_CLK_FIX))
|
||||
+ dcri_clrset(SDR0, SDR0_ETH_CFG,
|
||||
+ 0x00000100 >> dev->cell_index, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -2587,7 +2596,7 @@ static int emac_init_config(struct emac_
|
||||
if (of_device_is_compatible(np, "ibm,emac-apm821xx")) {
|
||||
dev->features |= (EMAC_APM821XX_REQ_JUMBO_FRAME_SIZE |
|
||||
EMAC_FTR_APM821XX_NO_HALF_DUPLEX |
|
||||
- EMAC_FTR_460EX_PHY_CLK_FIX);
|
||||
+ EMAC_FTR_APM821XX_PHY_CLK_FIX);
|
||||
}
|
||||
} else if (of_device_is_compatible(np, "ibm,emac4")) {
|
||||
dev->features |= EMAC_FTR_EMAC4;
|
||||
--- a/drivers/net/ethernet/ibm/emac/core.h
|
||||
+++ b/drivers/net/ethernet/ibm/emac/core.h
|
||||
@@ -333,6 +333,8 @@ struct emac_instance {
|
||||
*/
|
||||
#define EMAC_FTR_APM821XX_NO_HALF_DUPLEX 0x00001000
|
||||
|
||||
+#define EMAC_FTR_APM821XX_PHY_CLK_FIX 0x000002000
|
||||
+
|
||||
/* Right now, we don't quite handle the always/possible masks on the
|
||||
* most optimal way as we don't have a way to say something like
|
||||
* always EMAC4. Patches welcome.
|
|
@ -1,328 +0,0 @@
|
|||
From 59b394d0d2b2e11687e757820c52d6470d15a9c5 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Lamparter <chunkeey@gmail.com>
|
||||
Date: Mon, 13 Jun 2016 15:42:21 +0200
|
||||
Subject: [PATCH] phy device tree support for emac
|
||||
|
||||
---
|
||||
drivers/net/ethernet/ibm/emac/core.c | 261 +++++++++++++++++++++++++++++++++++
|
||||
drivers/net/ethernet/ibm/emac/core.h | 4 +
|
||||
2 files changed, 265 insertions(+)
|
||||
|
||||
--- a/drivers/net/ethernet/ibm/emac/core.c
|
||||
+++ b/drivers/net/ethernet/ibm/emac/core.c
|
||||
@@ -42,6 +42,7 @@
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_net.h>
|
||||
+#include <linux/of_mdio.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <asm/processor.h>
|
||||
@@ -2392,6 +2393,246 @@ static int emac_read_uint_prop(struct de
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static void emac_adjust_link(struct net_device *ndev)
|
||||
+{
|
||||
+ struct emac_instance *dev = netdev_priv(ndev);
|
||||
+ struct phy_device *phy = dev->phy_dev;
|
||||
+
|
||||
+ dev->phy.autoneg = phy->autoneg;
|
||||
+ dev->phy.speed = phy->speed;
|
||||
+ dev->phy.duplex = phy->duplex;
|
||||
+ dev->phy.pause = phy->pause;
|
||||
+ dev->phy.asym_pause = phy->asym_pause;
|
||||
+ dev->phy.advertising = phy->advertising;
|
||||
+}
|
||||
+
|
||||
+static int emac_mii_bus_read(struct mii_bus *bus, int addr, int regnum)
|
||||
+{
|
||||
+ return emac_mdio_read(bus->priv, addr, regnum);
|
||||
+}
|
||||
+
|
||||
+static int emac_mii_bus_write(struct mii_bus *bus, int addr, int regnum, u16 val)
|
||||
+{
|
||||
+ emac_mdio_write(bus->priv, addr, regnum, val);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int emac_mii_bus_reset(struct mii_bus *bus)
|
||||
+{
|
||||
+ struct emac_instance *dev = netdev_priv(bus->priv);
|
||||
+
|
||||
+ emac_mii_reset_phy(&dev->phy);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int emac_mdio_setup_aneg(struct mii_phy *phy, u32 advertise)
|
||||
+{
|
||||
+ struct net_device *ndev = phy->dev;
|
||||
+ struct emac_instance *dev = netdev_priv(ndev);
|
||||
+
|
||||
+ dev->phy.autoneg = AUTONEG_ENABLE;
|
||||
+ dev->phy.speed = SPEED_1000;
|
||||
+ dev->phy.duplex = DUPLEX_FULL;
|
||||
+ dev->phy.advertising = advertise;
|
||||
+ phy->autoneg = AUTONEG_ENABLE;
|
||||
+ phy->speed = dev->phy.speed;
|
||||
+ phy->duplex = dev->phy.duplex;
|
||||
+ phy->advertising = advertise;
|
||||
+ return phy_start_aneg(dev->phy_dev);
|
||||
+}
|
||||
+
|
||||
+static int emac_mdio_setup_forced(struct mii_phy *phy, int speed, int fd)
|
||||
+{
|
||||
+ struct net_device *ndev = phy->dev;
|
||||
+ struct emac_instance *dev = netdev_priv(ndev);
|
||||
+
|
||||
+ dev->phy.autoneg = AUTONEG_DISABLE;
|
||||
+ dev->phy.speed = speed;
|
||||
+ dev->phy.duplex = fd;
|
||||
+ phy->autoneg = AUTONEG_DISABLE;
|
||||
+ phy->speed = speed;
|
||||
+ phy->duplex = fd;
|
||||
+ return phy_start_aneg(dev->phy_dev);
|
||||
+}
|
||||
+
|
||||
+static int emac_mdio_poll_link(struct mii_phy *phy)
|
||||
+{
|
||||
+ struct net_device *ndev = phy->dev;
|
||||
+ struct emac_instance *dev = netdev_priv(ndev);
|
||||
+ int res;
|
||||
+
|
||||
+ res = phy_read_status(dev->phy_dev);
|
||||
+ if (res) {
|
||||
+ dev_err(&dev->ndev->dev, "link update failed (%d).", res);
|
||||
+ return ethtool_op_get_link(ndev);
|
||||
+ }
|
||||
+
|
||||
+ return dev->phy_dev->link;
|
||||
+}
|
||||
+
|
||||
+static int emac_mdio_read_link(struct mii_phy *phy)
|
||||
+{
|
||||
+ struct net_device *ndev = phy->dev;
|
||||
+ struct emac_instance *dev = netdev_priv(ndev);
|
||||
+ int res;
|
||||
+
|
||||
+ res = phy_read_status(dev->phy_dev);
|
||||
+ if (res)
|
||||
+ return res;
|
||||
+
|
||||
+ dev->phy.speed = phy->speed;
|
||||
+ dev->phy.duplex = phy->duplex;
|
||||
+ dev->phy.pause = phy->pause;
|
||||
+ dev->phy.asym_pause = phy->asym_pause;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int emac_mdio_init_phy(struct mii_phy *phy)
|
||||
+{
|
||||
+ struct net_device *ndev = phy->dev;
|
||||
+ struct emac_instance *dev = netdev_priv(ndev);
|
||||
+
|
||||
+ phy_start(dev->phy_dev);
|
||||
+ dev->phy.autoneg = phy->autoneg;
|
||||
+ dev->phy.speed = phy->speed;
|
||||
+ dev->phy.duplex = phy->duplex;
|
||||
+ dev->phy.advertising = phy->advertising;
|
||||
+ dev->phy.pause = phy->pause;
|
||||
+ dev->phy.asym_pause = phy->asym_pause;
|
||||
+
|
||||
+ return phy_init_hw(dev->phy_dev);
|
||||
+}
|
||||
+
|
||||
+static const struct mii_phy_ops emac_dt_mdio_phy_ops = {
|
||||
+ .init = emac_mdio_init_phy,
|
||||
+ .setup_aneg = emac_mdio_setup_aneg,
|
||||
+ .setup_forced = emac_mdio_setup_forced,
|
||||
+ .poll_link = emac_mdio_poll_link,
|
||||
+ .read_link = emac_mdio_read_link,
|
||||
+};
|
||||
+
|
||||
+static void emac_dt_phy_mdio_cleanup(struct emac_instance *dev)
|
||||
+{
|
||||
+ if (dev->mii_bus) {
|
||||
+ if (dev->mii_bus->state == MDIOBUS_REGISTERED)
|
||||
+ mdiobus_unregister(dev->mii_bus);
|
||||
+ mdiobus_free(dev->mii_bus);
|
||||
+ dev->mii_bus = NULL;
|
||||
+ }
|
||||
+ kfree(dev->phy.def);
|
||||
+ dev->phy.def = NULL;
|
||||
+}
|
||||
+
|
||||
+static int emac_dt_mdio_probe(struct emac_instance *dev)
|
||||
+{
|
||||
+ struct device_node *mii_np;
|
||||
+ int res;
|
||||
+
|
||||
+ mii_np = of_get_child_by_name(dev->ofdev->dev.of_node, "mdio");
|
||||
+ if (!mii_np) {
|
||||
+ dev_err(&dev->ndev->dev, "no mdio definition found.");
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+
|
||||
+ if (!of_device_is_available(mii_np)) {
|
||||
+ res = 1;
|
||||
+ goto err_put_node;
|
||||
+ }
|
||||
+
|
||||
+ dev->mii_bus = mdiobus_alloc();
|
||||
+ if (!dev->mii_bus) {
|
||||
+ res = -ENOMEM;
|
||||
+ goto err_cleanup_mdio;
|
||||
+ }
|
||||
+
|
||||
+ dev->mii_bus->priv = dev->ndev;
|
||||
+ dev->mii_bus->parent = dev->ndev->dev.parent;
|
||||
+ dev->mii_bus->name = "emac_mdio";
|
||||
+ dev->mii_bus->read = &emac_mii_bus_read;
|
||||
+ dev->mii_bus->write = &emac_mii_bus_write;
|
||||
+ dev->mii_bus->reset = &emac_mii_bus_reset;
|
||||
+ snprintf(dev->mii_bus->id, MII_BUS_ID_SIZE, "%s", dev->mii_bus->name);
|
||||
+
|
||||
+ res = of_mdiobus_register(dev->mii_bus, mii_np);
|
||||
+ if (res) {
|
||||
+ dev_err(&dev->ndev->dev, "cannot register MDIO bus %s (%d)",
|
||||
+ dev->mii_bus->name, res);
|
||||
+ goto err_cleanup_mdio;
|
||||
+ }
|
||||
+ of_node_put(mii_np);
|
||||
+ return 0;
|
||||
+
|
||||
+ err_cleanup_mdio:
|
||||
+ emac_dt_phy_mdio_cleanup(dev);
|
||||
+ err_put_node:
|
||||
+ of_node_put(mii_np);
|
||||
+ return res;
|
||||
+}
|
||||
+
|
||||
+static int emac_dt_phy_probe(struct emac_instance *dev,
|
||||
+ struct device_node *phy_handle)
|
||||
+{
|
||||
+ u32 phy_flags = 0;
|
||||
+ int res;
|
||||
+
|
||||
+ res = of_property_read_u32(phy_handle, "phy-flags", &phy_flags);
|
||||
+ if (res < 0 && res != -EINVAL)
|
||||
+ return res;
|
||||
+
|
||||
+ dev->phy.def = kzalloc(sizeof(*dev->phy.def), GFP_KERNEL);
|
||||
+ if (!dev->phy.def)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ dev->phy_dev = of_phy_connect(dev->ndev, phy_handle,
|
||||
+ &emac_adjust_link, phy_flags,
|
||||
+ PHY_INTERFACE_MODE_RGMII);
|
||||
+ if (!dev->phy_dev) {
|
||||
+ dev_err(&dev->ndev->dev, "failed to connect to PHY.");
|
||||
+ kfree(dev->phy.dev);
|
||||
+ dev->phy.dev = NULL;
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+
|
||||
+ dev->phy.def->phy_id = dev->phy_dev->drv->phy_id;
|
||||
+ dev->phy.def->phy_id_mask = dev->phy_dev->drv->phy_id_mask;
|
||||
+ dev->phy.def->name = dev->phy_dev->drv->name;
|
||||
+ dev->phy.def->ops = &emac_dt_mdio_phy_ops;
|
||||
+ dev->phy.features = dev->phy_dev->supported;
|
||||
+ dev->phy.address = dev->phy_dev->addr;
|
||||
+ dev->phy.mode = dev->phy_dev->interface;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int emac_probe_dt_phy(struct emac_instance *dev)
|
||||
+{
|
||||
+ struct device_node *np = dev->ofdev->dev.of_node;
|
||||
+ struct device_node *phy_handle;
|
||||
+ int res = 0;
|
||||
+
|
||||
+ phy_handle = of_parse_phandle(np, "phy-handle", 0);
|
||||
+
|
||||
+ if (phy_handle) {
|
||||
+ res = emac_dt_mdio_probe(dev);
|
||||
+ if (res)
|
||||
+ goto out;
|
||||
+
|
||||
+ res = emac_dt_phy_probe(dev, phy_handle);
|
||||
+ if (res) {
|
||||
+ emac_dt_phy_mdio_cleanup(dev);
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ out:
|
||||
+ of_node_put(phy_handle);
|
||||
+ /* if no phy device was specifie in the device tree, then we fallback
|
||||
+ * to the old emac_phy.c probe code for compatibility reasons.
|
||||
+ */
|
||||
+ return res;
|
||||
+}
|
||||
+
|
||||
static int emac_init_phy(struct emac_instance *dev)
|
||||
{
|
||||
struct device_node *np = dev->ofdev->dev.of_node;
|
||||
@@ -2462,6 +2703,18 @@ static int emac_init_phy(struct emac_ins
|
||||
|
||||
emac_configure(dev);
|
||||
|
||||
+ if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII)) {
|
||||
+ int res = emac_probe_dt_phy(dev);
|
||||
+
|
||||
+ if (res == 1)
|
||||
+ goto init_phy;
|
||||
+ if (res < 0)
|
||||
+ dev_err(&dev->ndev->dev, "failed to attach dt phy (%d).",
|
||||
+ res);
|
||||
+
|
||||
+ /* continue with old code */
|
||||
+ }
|
||||
+
|
||||
if (dev->phy_address != 0xffffffff)
|
||||
phy_map = ~(1 << dev->phy_address);
|
||||
|
||||
@@ -2489,6 +2742,7 @@ static int emac_init_phy(struct emac_ins
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
+ init_phy:
|
||||
/* Init PHY */
|
||||
if (dev->phy.def->ops->init)
|
||||
dev->phy.def->ops->init(&dev->phy);
|
||||
@@ -2907,6 +3161,8 @@ static int emac_probe(struct platform_de
|
||||
/* I have a bad feeling about this ... */
|
||||
|
||||
err_detach_tah:
|
||||
+ emac_dt_phy_mdio_cleanup(dev);
|
||||
+
|
||||
if (emac_has_feature(dev, EMAC_FTR_HAS_TAH))
|
||||
tah_detach(dev->tah_dev, dev->tah_port);
|
||||
err_detach_rgmii:
|
||||
@@ -2957,6 +3213,11 @@ static int emac_remove(struct platform_d
|
||||
if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII))
|
||||
zmii_detach(dev->zmii_dev, dev->zmii_port);
|
||||
|
||||
+ if (dev->phy_dev)
|
||||
+ phy_disconnect(dev->phy_dev);
|
||||
+
|
||||
+ emac_dt_phy_mdio_cleanup(dev);
|
||||
+
|
||||
busy_phy_map &= ~(1 << dev->phy.address);
|
||||
DBG(dev, "busy_phy_map now %#x" NL, busy_phy_map);
|
||||
|
||||
--- a/drivers/net/ethernet/ibm/emac/core.h
|
||||
+++ b/drivers/net/ethernet/ibm/emac/core.h
|
||||
@@ -199,6 +199,10 @@ struct emac_instance {
|
||||
struct emac_instance *mdio_instance;
|
||||
struct mutex mdio_lock;
|
||||
|
||||
+ /* Device-tree based phy configuration */
|
||||
+ struct mii_bus *mii_bus;
|
||||
+ struct phy_device *phy_dev;
|
||||
+
|
||||
/* ZMII infos if any */
|
||||
u32 zmii_ph;
|
||||
u32 zmii_port;
|
|
@ -1,545 +0,0 @@
|
|||
From 419992bae5aaa4e06402e0b7c79fcf7bcb6b4764 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Lamparter <chunkeey@googlemail.com>
|
||||
Date: Thu, 2 Jun 2016 00:48:46 +0200
|
||||
Subject: [PATCH] usb: xhci: add firmware loader for uPD720201 and uPD720202
|
||||
w/o ROM
|
||||
|
||||
This patch adds a firmware loader for the uPD720201K8-711-BAC-A
|
||||
and uPD720202K8-711-BAA-A variant. Both of these chips are listed
|
||||
in Renesas' R19UH0078EJ0500 Rev.5.00 "User's Manual: Hardware" as
|
||||
devices which need the firmware loader on page 2 in order to
|
||||
work as they "do not support the External ROM".
|
||||
|
||||
The "Firmware Download Sequence" is describe in chapter
|
||||
"7.1 FW Download Interface" R19UH0078EJ0500 Rev.5.00 page 131.
|
||||
|
||||
The firmware "K2013080.mem" is available from a USB3.0 Host to
|
||||
PCIe Adapter (PP2U-E card) "Firmware download" archive. An
|
||||
alternative version can be sourced from Netgear's WNDR4700 GPL
|
||||
archives.
|
||||
|
||||
The release notes of the PP2U-E's "Firmware Download" ver 2.0.1.3
|
||||
(2012-06-15) state that the firmware is for the following devices:
|
||||
- uPD720201 ES 2.0 sample whose revision ID is 2.
|
||||
- uPD720201 ES 2.1 sample & CS sample & Mass product, ID is 3.
|
||||
- uPD720202 ES 2.0 sample & CS sample & Mass product, ID is 2.
|
||||
|
||||
If someone from Renesas is listening: It would be great, if these
|
||||
firmwares could be added to linux-firmware.git.
|
||||
|
||||
Cc: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
|
||||
Signed-off-by: Christian Lamparter <chunkeey@googlemail.com>
|
||||
---
|
||||
drivers/usb/host/xhci-pci.c | 492 ++++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 492 insertions(+)
|
||||
|
||||
--- a/drivers/usb/host/xhci-pci.c
|
||||
+++ b/drivers/usb/host/xhci-pci.c
|
||||
@@ -24,6 +24,8 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/acpi.h>
|
||||
+#include <linux/firmware.h>
|
||||
+#include <asm/unaligned.h>
|
||||
|
||||
#include "xhci.h"
|
||||
#include "xhci-trace.h"
|
||||
@@ -218,6 +220,458 @@ static void xhci_pme_acpi_rtd3_enable(st
|
||||
static void xhci_pme_acpi_rtd3_enable(struct pci_dev *dev) { }
|
||||
#endif /* CONFIG_ACPI */
|
||||
|
||||
+static const struct renesas_fw_entry {
|
||||
+ const char *firmware_name;
|
||||
+ u16 device;
|
||||
+ u8 revision;
|
||||
+ u16 expected_version;
|
||||
+} renesas_fw_table[] = {
|
||||
+ /*
|
||||
+ * Only the uPD720201K8-711-BAC-A or uPD720202K8-711-BAA-A
|
||||
+ * are listed in R19UH0078EJ0500 Rev.5.00 as devices which
|
||||
+ * need the software loader.
|
||||
+ *
|
||||
+ * PP2U/ReleaseNote_USB3-201-202-FW.txt:
|
||||
+ *
|
||||
+ * Note: This firmware is for the following devices.
|
||||
+ * - uPD720201 ES 2.0 sample whose revision ID is 2.
|
||||
+ * - uPD720201 ES 2.1 sample & CS sample & Mass product, ID is 3.
|
||||
+ * - uPD720202 ES 2.0 sample & CS sample & Mass product, ID is 2.
|
||||
+ */
|
||||
+ { "K2013080.mem", 0x0014, 0x02, 0x2013 },
|
||||
+ { "K2013080.mem", 0x0014, 0x03, 0x2013 },
|
||||
+ { "K2013080.mem", 0x0015, 0x02, 0x2013 },
|
||||
+};
|
||||
+
|
||||
+static const struct renesas_fw_entry *renesas_needs_fw_dl(struct pci_dev *dev)
|
||||
+{
|
||||
+ const struct renesas_fw_entry *entry;
|
||||
+ size_t i;
|
||||
+
|
||||
+ /* This loader will only work with a RENESAS device. */
|
||||
+ if (!(dev->vendor == PCI_VENDOR_ID_RENESAS))
|
||||
+ return NULL;
|
||||
+
|
||||
+ for (i = 0; i < ARRAY_SIZE(renesas_fw_table); i++) {
|
||||
+ entry = &renesas_fw_table[i];
|
||||
+ if (entry->device == dev->device &&
|
||||
+ entry->revision == dev->revision)
|
||||
+ return entry;
|
||||
+ }
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+static int renesas_fw_download_image(struct pci_dev *dev,
|
||||
+ const u32 *fw,
|
||||
+ size_t step)
|
||||
+{
|
||||
+ size_t i;
|
||||
+ int err;
|
||||
+ u8 fw_status;
|
||||
+ bool data0_or_data1;
|
||||
+
|
||||
+ /*
|
||||
+ * The hardware does alternate between two 32-bit pages.
|
||||
+ * (This is because each row of the firmware is 8 bytes).
|
||||
+ *
|
||||
+ * for even steps we use DATA0, for odd steps DATA1.
|
||||
+ */
|
||||
+ data0_or_data1 = (step & 1) == 1;
|
||||
+
|
||||
+ /* step+1. Read "Set DATAX" and confirm it is cleared. */
|
||||
+ for (i = 0; i < 10000; i++) {
|
||||
+ err = pci_read_config_byte(dev, 0xF5, &fw_status);
|
||||
+ if (err)
|
||||
+ return pcibios_err_to_errno(err);
|
||||
+ if (!(fw_status & BIT(data0_or_data1)))
|
||||
+ break;
|
||||
+
|
||||
+ udelay(1);
|
||||
+ }
|
||||
+ if (i == 10000)
|
||||
+ return -ETIMEDOUT;
|
||||
+
|
||||
+ /*
|
||||
+ * step+2. Write FW data to "DATAX".
|
||||
+ * "LSB is left" => force little endian
|
||||
+ */
|
||||
+ err = pci_write_config_dword(dev, data0_or_data1 ? 0xFC : 0xF8,
|
||||
+ (__force u32) cpu_to_le32(fw[step]));
|
||||
+ if (err)
|
||||
+ return pcibios_err_to_errno(err);
|
||||
+
|
||||
+ udelay(100);
|
||||
+
|
||||
+ /* step+3. Set "Set DATAX". */
|
||||
+ err = pci_write_config_byte(dev, 0xF5, BIT(data0_or_data1));
|
||||
+ if (err)
|
||||
+ return pcibios_err_to_errno(err);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int renesas_fw_verify(struct pci_dev *dev,
|
||||
+ const void *fw_data,
|
||||
+ size_t length)
|
||||
+{
|
||||
+ const struct renesas_fw_entry *entry = renesas_needs_fw_dl(dev);
|
||||
+ u16 fw_version_pointer;
|
||||
+ u16 fw_version;
|
||||
+
|
||||
+ if (!entry)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ /*
|
||||
+ * The Firmware's Data Format is describe in
|
||||
+ * "6.3 Data Format" R19UH0078EJ0500 Rev.5.00 page 124
|
||||
+ */
|
||||
+
|
||||
+ /* "Each row is 8 bytes". => firmware size must be a multiple of 8. */
|
||||
+ if (length % 8 != 0) {
|
||||
+ dev_err(&dev->dev, "firmware size is not a multipe of 8.");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * The bootrom chips of the big brother have sizes up to 64k, let's
|
||||
+ * assume that's the biggest the firmware can get.
|
||||
+ */
|
||||
+ if (length < 0x1000 || length >= 0x10000) {
|
||||
+ dev_err(&dev->dev, "firmware is size %zd is not (4k - 64k).",
|
||||
+ length);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ /* The First 2 bytes are fixed value (55aa). "LSB on Left" */
|
||||
+ if (get_unaligned_le16(fw_data) != 0x55aa) {
|
||||
+ dev_err(&dev->dev, "no valid firmware header found.");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ /* verify the firmware version position and print it. */
|
||||
+ fw_version_pointer = get_unaligned_le16(fw_data + 4);
|
||||
+ if (fw_version_pointer + 2 >= length) {
|
||||
+ dev_err(&dev->dev, "firmware version pointer is outside of the firmware image.");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ fw_version = get_unaligned_le16(fw_data + fw_version_pointer);
|
||||
+ dev_dbg(&dev->dev, "got firmware version: %02x.", fw_version);
|
||||
+
|
||||
+ if (fw_version != entry->expected_version) {
|
||||
+ dev_err(&dev->dev, "firmware version mismatch, expected version: %02x.",
|
||||
+ entry->expected_version);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int renesas_fw_check_running(struct pci_dev *pdev)
|
||||
+{
|
||||
+ int err;
|
||||
+ u8 fw_state;
|
||||
+
|
||||
+ /*
|
||||
+ * Test if the device is actually needing the firmware. As most
|
||||
+ * BIOSes will initialize the device for us. If the device is
|
||||
+ * initialized.
|
||||
+ */
|
||||
+ err = pci_read_config_byte(pdev, 0xF4, &fw_state);
|
||||
+ if (err)
|
||||
+ return pcibios_err_to_errno(err);
|
||||
+
|
||||
+ /*
|
||||
+ * Check if "FW Download Lock" is locked. If it is and the FW is
|
||||
+ * ready we can simply continue. If the FW is not ready, we have
|
||||
+ * to give up.
|
||||
+ */
|
||||
+ if (fw_state & BIT(1)) {
|
||||
+ dev_dbg(&pdev->dev, "FW Download Lock is engaged.");
|
||||
+
|
||||
+ if (fw_state & BIT(4))
|
||||
+ return 0;
|
||||
+
|
||||
+ dev_err(&pdev->dev, "FW Download Lock is set and FW is not ready. Giving Up.");
|
||||
+ return -EIO;
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * Check if "FW Download Enable" is set. If someone (us?) tampered
|
||||
+ * with it and it can't be resetted, we have to give up too... and
|
||||
+ * ask for a forgiveness and a reboot.
|
||||
+ */
|
||||
+ if (fw_state & BIT(0)) {
|
||||
+ dev_err(&pdev->dev, "FW Download Enable is stale. Giving Up (poweroff/reboot needed).");
|
||||
+ return -EIO;
|
||||
+ }
|
||||
+
|
||||
+ /* Otherwise, Check the "Result Code" Bits (6:4) and act accordingly */
|
||||
+ switch ((fw_state & 0x70)) {
|
||||
+ case 0: /* No result yet */
|
||||
+ dev_dbg(&pdev->dev, "FW is not ready/loaded yet.");
|
||||
+
|
||||
+ /* tell the caller, that this device needs the firmware. */
|
||||
+ return 1;
|
||||
+
|
||||
+ case BIT(4): /* Success, device should be working. */
|
||||
+ dev_dbg(&pdev->dev, "FW is ready.");
|
||||
+ return 0;
|
||||
+
|
||||
+ case BIT(5): /* Error State */
|
||||
+ dev_err(&pdev->dev, "hardware is in an error state. Giving up (poweroff/reboot needed).");
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ default: /* All other states are marked as "Reserved states" */
|
||||
+ dev_err(&pdev->dev, "hardware is in an invalid state %x. Giving up (poweroff/reboot needed).",
|
||||
+ (fw_state & 0x70) >> 4);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static int renesas_hw_check_run_stop_busy(struct pci_dev *pdev)
|
||||
+{
|
||||
+#if 0
|
||||
+ u32 val;
|
||||
+
|
||||
+ /*
|
||||
+ * 7.1.3 Note 3: "... must not set 'FW Download Enable' when
|
||||
+ * 'RUN/STOP' of USBCMD Register is set"
|
||||
+ */
|
||||
+ val = readl(hcd->regs + 0x20);
|
||||
+ if (val & BIT(0)) {
|
||||
+ dev_err(&pdev->dev, "hardware is busy and can't receive a FW.");
|
||||
+ return -EBUSY;
|
||||
+ }
|
||||
+#endif
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int renesas_fw_download(struct pci_dev *pdev,
|
||||
+ const struct firmware *fw, unsigned int retry_counter)
|
||||
+{
|
||||
+ const u32 *fw_data = (const u32 *) fw->data;
|
||||
+ size_t i;
|
||||
+ int err;
|
||||
+ u8 fw_status;
|
||||
+
|
||||
+ /*
|
||||
+ * For more information and the big picture: please look at the
|
||||
+ * "Firmware Download Sequence" in "7.1 FW Download Interface"
|
||||
+ * of R19UH0078EJ0500 Rev.5.00 page 131
|
||||
+ */
|
||||
+ err = renesas_hw_check_run_stop_busy(pdev);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ /*
|
||||
+ * 0. Set "FW Download Enable" bit in the
|
||||
+ * "FW Download Control & Status Register" at 0xF4
|
||||
+ */
|
||||
+ err = pci_write_config_byte(pdev, 0xF4, BIT(0));
|
||||
+ if (err)
|
||||
+ return pcibios_err_to_errno(err);
|
||||
+
|
||||
+ /* 1 - 10 follow one step after the other. */
|
||||
+ for (i = 0; i < fw->size / 4; i++) {
|
||||
+ err = renesas_fw_download_image(pdev, fw_data, i);
|
||||
+ if (err) {
|
||||
+ dev_err(&pdev->dev, "Firmware Download Step %zd failed at position %zd bytes with (%d).",
|
||||
+ i, i * 4, err);
|
||||
+ return err;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * This sequence continues until the last data is written to
|
||||
+ * "DATA0" or "DATA1". Naturally, we wait until "SET DATA0/1"
|
||||
+ * is cleared by the hardware beforehand.
|
||||
+ */
|
||||
+ for (i = 0; i < 10000; i++) {
|
||||
+ err = pci_read_config_byte(pdev, 0xF5, &fw_status);
|
||||
+ if (err)
|
||||
+ return pcibios_err_to_errno(err);
|
||||
+ if (!(fw_status & (BIT(0) | BIT(1))))
|
||||
+ break;
|
||||
+
|
||||
+ udelay(1);
|
||||
+ }
|
||||
+ if (i == 10000)
|
||||
+ dev_warn(&pdev->dev, "Final Firmware Download step timed out.");
|
||||
+
|
||||
+ /*
|
||||
+ * 11. After finishing writing the last data of FW, the
|
||||
+ * System Software must clear "FW Download Enable"
|
||||
+ */
|
||||
+ err = pci_write_config_byte(pdev, 0xF4, 0);
|
||||
+ if (err)
|
||||
+ return pcibios_err_to_errno(err);
|
||||
+
|
||||
+ /* 12. Read "Result Code" and confirm it is good. */
|
||||
+ for (i = 0; i < 10000; i++) {
|
||||
+ err = pci_read_config_byte(pdev, 0xF4, &fw_status);
|
||||
+ if (err)
|
||||
+ return pcibios_err_to_errno(err);
|
||||
+ if (fw_status & BIT(4))
|
||||
+ break;
|
||||
+
|
||||
+ udelay(1);
|
||||
+ }
|
||||
+ if (i == 10000) {
|
||||
+ /* Timed out / Error - let's see if we can fix this */
|
||||
+ err = renesas_fw_check_running(pdev);
|
||||
+ switch (err) {
|
||||
+ case 0: /*
|
||||
+ * we shouldn't end up here.
|
||||
+ * maybe it took a little bit longer.
|
||||
+ * But all should be well?
|
||||
+ */
|
||||
+ break;
|
||||
+
|
||||
+ case 1: /* (No result yet? - we can try to retry) */
|
||||
+ if (retry_counter < 10) {
|
||||
+ retry_counter++;
|
||||
+ dev_warn(&pdev->dev, "Retry Firmware download: %d try.",
|
||||
+ retry_counter);
|
||||
+ return renesas_fw_download(pdev, fw,
|
||||
+ retry_counter);
|
||||
+ }
|
||||
+ return -ETIMEDOUT;
|
||||
+
|
||||
+ default:
|
||||
+ return err;
|
||||
+ }
|
||||
+ }
|
||||
+ /*
|
||||
+ * Optional last step: Engage Firmware Lock
|
||||
+ *
|
||||
+ * err = pci_write_config_byte(pdev, 0xF4, BIT(2));
|
||||
+ * if (err)
|
||||
+ * return pcibios_err_to_errno(err);
|
||||
+ */
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+struct renesas_fw_ctx {
|
||||
+ struct pci_dev *pdev;
|
||||
+ const struct pci_device_id *id;
|
||||
+ bool resume;
|
||||
+};
|
||||
+
|
||||
+static int xhci_pci_probe(struct pci_dev *pdev,
|
||||
+ const struct pci_device_id *id);
|
||||
+
|
||||
+static void renesas_fw_callback(const struct firmware *fw,
|
||||
+ void *context)
|
||||
+{
|
||||
+ struct renesas_fw_ctx *ctx = context;
|
||||
+ struct pci_dev *pdev = ctx->pdev;
|
||||
+ struct device *parent = pdev->dev.parent;
|
||||
+ int err = -ENOENT;
|
||||
+
|
||||
+ if (fw) {
|
||||
+ err = renesas_fw_verify(pdev, fw->data, fw->size);
|
||||
+ if (!err) {
|
||||
+ err = renesas_fw_download(pdev, fw, 0);
|
||||
+ release_firmware(fw);
|
||||
+ if (!err) {
|
||||
+ if (ctx->resume)
|
||||
+ return;
|
||||
+
|
||||
+ err = xhci_pci_probe(pdev, ctx->id);
|
||||
+ if (!err) {
|
||||
+ /* everything worked */
|
||||
+ devm_kfree(&pdev->dev, ctx);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ /* in case of an error - fall through */
|
||||
+ } else {
|
||||
+ dev_err(&pdev->dev, "firmware failed to download (%d).",
|
||||
+ err);
|
||||
+ }
|
||||
+ }
|
||||
+ } else {
|
||||
+ dev_err(&pdev->dev, "firmware failed to load (%d).", err);
|
||||
+ }
|
||||
+
|
||||
+ dev_info(&pdev->dev, "Unloading driver");
|
||||
+
|
||||
+ if (parent)
|
||||
+ device_lock(parent);
|
||||
+
|
||||
+ device_release_driver(&pdev->dev);
|
||||
+
|
||||
+ if (parent)
|
||||
+ device_unlock(parent);
|
||||
+
|
||||
+ pci_dev_put(pdev);
|
||||
+}
|
||||
+
|
||||
+static int renesas_fw_alive_check(struct pci_dev *pdev)
|
||||
+{
|
||||
+ const struct renesas_fw_entry *entry;
|
||||
+ int err;
|
||||
+
|
||||
+ /* check if we have a eligible RENESAS' uPD720201/2 w/o FW. */
|
||||
+ entry = renesas_needs_fw_dl(pdev);
|
||||
+ if (!entry)
|
||||
+ return 0;
|
||||
+
|
||||
+ err = renesas_fw_check_running(pdev);
|
||||
+ /* Also go ahead, if the firmware is running */
|
||||
+ if (err == 0)
|
||||
+ return 0;
|
||||
+
|
||||
+ /* At this point, we can be sure that the FW isn't ready. */
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+static int renesas_fw_download_to_hw(struct pci_dev *pdev,
|
||||
+ const struct pci_device_id *id,
|
||||
+ bool do_resume)
|
||||
+{
|
||||
+ const struct renesas_fw_entry *entry;
|
||||
+ struct renesas_fw_ctx *ctx;
|
||||
+ int err;
|
||||
+
|
||||
+ /* check if we have a eligible RENESAS' uPD720201/2 w/o FW. */
|
||||
+ entry = renesas_needs_fw_dl(pdev);
|
||||
+ if (!entry)
|
||||
+ return 0;
|
||||
+
|
||||
+ err = renesas_fw_check_running(pdev);
|
||||
+ /* Continue ahead, if the firmware is already running. */
|
||||
+ if (err == 0)
|
||||
+ return 0;
|
||||
+
|
||||
+ if (err != 1)
|
||||
+ return err;
|
||||
+
|
||||
+ ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
|
||||
+ if (!ctx)
|
||||
+ return -ENOMEM;
|
||||
+ ctx->pdev = pdev;
|
||||
+ ctx->resume = do_resume;
|
||||
+ ctx->id = id;
|
||||
+
|
||||
+ pci_dev_get(pdev);
|
||||
+ err = request_firmware_nowait(THIS_MODULE, 1, entry->firmware_name,
|
||||
+ &pdev->dev, GFP_KERNEL, ctx, renesas_fw_callback);
|
||||
+ if (err) {
|
||||
+ pci_dev_put(pdev);
|
||||
+ return err;
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * The renesas_fw_callback() callback will continue the probe
|
||||
+ * process, once it aquires the firmware.
|
||||
+ */
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
/* called during probe() after chip reset completes */
|
||||
static int xhci_pci_setup(struct usb_hcd *hcd)
|
||||
{
|
||||
@@ -257,6 +711,22 @@ static int xhci_pci_probe(struct pci_dev
|
||||
struct hc_driver *driver;
|
||||
struct usb_hcd *hcd;
|
||||
|
||||
+ /*
|
||||
+ * Check if this device is a RENESAS uPD720201/2 device.
|
||||
+ * Otherwise, we can continue with xhci_pci_probe as usual.
|
||||
+ */
|
||||
+ retval = renesas_fw_download_to_hw(dev, id, false);
|
||||
+ switch (retval) {
|
||||
+ case 0:
|
||||
+ break;
|
||||
+
|
||||
+ case 1: /* let it load the firmware and recontinue the probe. */
|
||||
+ return 0;
|
||||
+
|
||||
+ default:
|
||||
+ return retval;
|
||||
+ };
|
||||
+
|
||||
driver = (struct hc_driver *)id->driver_data;
|
||||
|
||||
/* Prevent runtime suspending between USB-2 and USB-3 initialization */
|
||||
@@ -314,6 +784,16 @@ static void xhci_pci_remove(struct pci_d
|
||||
{
|
||||
struct xhci_hcd *xhci;
|
||||
|
||||
+ if (renesas_fw_alive_check(dev)) {
|
||||
+ /*
|
||||
+ * bail out early, if this was a renesas device w/o FW.
|
||||
+ * Else we might hit the NMI watchdog in xhci_handsake
|
||||
+ * during xhci_reset as part of the driver's unloading.
|
||||
+ * which we forced in the renesas_fw_callback().
|
||||
+ */
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
xhci = hcd_to_xhci(pci_get_drvdata(dev));
|
||||
xhci->xhc_state |= XHCI_STATE_REMOVING;
|
||||
if (xhci->shared_hcd) {
|
|
@ -1,54 +0,0 @@
|
|||
From a0dc613140bab907a3d5787a7ae7b0638bf674d0 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Lamparter <chunkeey@gmail.com>
|
||||
Date: Thu, 23 Jun 2016 20:28:20 +0200
|
||||
Subject: [PATCH] usb: xhci: force MSI for uPD720201 and
|
||||
uPD720202
|
||||
|
||||
The APM82181 does not support MSI-X. When probed, it will
|
||||
produce a noisy warning.
|
||||
|
||||
---
|
||||
drivers/usb/host/pci-quirks.c | 362 ++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 362 insertions(+)
|
||||
|
||||
--- a/drivers/usb/host/xhci-pci.c
|
||||
+++ b/drivers/usb/host/xhci-pci.c
|
||||
@@ -185,7 +185,7 @@ static void xhci_pci_quirks(struct devic
|
||||
}
|
||||
if (pdev->vendor == PCI_VENDOR_ID_RENESAS &&
|
||||
pdev->device == 0x0015)
|
||||
- xhci->quirks |= XHCI_RESET_ON_RESUME;
|
||||
+ xhci->quirks |= XHCI_RESET_ON_RESUME | XHCI_FORCE_MSI;
|
||||
if (pdev->vendor == PCI_VENDOR_ID_VIA)
|
||||
xhci->quirks |= XHCI_RESET_ON_RESUME;
|
||||
|
||||
--- a/drivers/usb/host/xhci.c
|
||||
+++ b/drivers/usb/host/xhci.c
|
||||
@@ -388,10 +388,14 @@ static int xhci_try_enable_msi(struct us
|
||||
free_irq(hcd->irq, hcd);
|
||||
hcd->irq = 0;
|
||||
|
||||
- ret = xhci_setup_msix(xhci);
|
||||
- if (ret)
|
||||
- /* fall back to msi*/
|
||||
+ if (xhci->quirks & XHCI_FORCE_MSI) {
|
||||
ret = xhci_setup_msi(xhci);
|
||||
+ } else {
|
||||
+ ret = xhci_setup_msix(xhci);
|
||||
+ if (ret)
|
||||
+ /* fall back to msi*/
|
||||
+ ret = xhci_setup_msi(xhci);
|
||||
+ }
|
||||
|
||||
if (!ret)
|
||||
/* hcd->irq is 0, we have MSI */
|
||||
--- a/drivers/usb/host/xhci.h
|
||||
+++ b/drivers/usb/host/xhci.h
|
||||
@@ -1652,6 +1652,7 @@ struct xhci_hcd {
|
||||
/* support xHCI 0.96 spec USB2 software LPM */
|
||||
unsigned sw_lpm_support:1;
|
||||
/* support xHCI 1.0 spec USB2 hardware LPM */
|
||||
+#define XHCI_FORCE_MSI (1 << 24)
|
||||
unsigned hw_lpm_support:1;
|
||||
/* cached usb2 extened protocol capabilites */
|
||||
u32 *ext_caps;
|
|
@ -1,48 +0,0 @@
|
|||
--- a/drivers/usb/dwc2/platform.c
|
||||
+++ b/drivers/usb/dwc2/platform.c
|
||||
@@ -115,6 +115,37 @@ static const struct dwc2_core_params par
|
||||
.hibernation = -1,
|
||||
};
|
||||
|
||||
+static const struct dwc2_core_params params_amcc_dwc_otg = {
|
||||
+ .otg_cap = DWC2_CAP_PARAM_HNP_SRP_CAPABLE,
|
||||
+ .otg_ver = -1,
|
||||
+ .dma_enable = -1,
|
||||
+ .dma_desc_enable = -1,
|
||||
+ .speed = -1,
|
||||
+ .enable_dynamic_fifo = -1,
|
||||
+ .en_multiple_tx_fifo = -1,
|
||||
+ .host_rx_fifo_size = -1,
|
||||
+ .host_nperio_tx_fifo_size = -1,
|
||||
+ .host_perio_tx_fifo_size = -1,
|
||||
+ .max_transfer_size = -1,
|
||||
+ .max_packet_count = -1,
|
||||
+ .host_channels = -1,
|
||||
+ .phy_type = -1,
|
||||
+ .phy_utmi_width = -1,
|
||||
+ .phy_ulpi_ddr = -1,
|
||||
+ .phy_ulpi_ext_vbus = -1,
|
||||
+ .i2c_enable = -1,
|
||||
+ .ulpi_fs_ls = -1,
|
||||
+ .host_support_fs_ls_low_power = -1,
|
||||
+ .host_ls_low_power_phy_clk = -1,
|
||||
+ .ts_dline = -1,
|
||||
+ .reload_ctl = -1,
|
||||
+ .ahbcfg = GAHBCFG_HBSTLEN_INCR16 <<
|
||||
+ GAHBCFG_HBSTLEN_SHIFT,
|
||||
+ .uframe_sched = -1,
|
||||
+ .external_id_pin_ctl = -1,
|
||||
+ .hibernation = -1,
|
||||
+};
|
||||
+
|
||||
static int __dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(hsotg->dev);
|
||||
@@ -307,6 +338,7 @@ static int dwc2_driver_remove(struct pla
|
||||
}
|
||||
|
||||
static const struct of_device_id dwc2_of_match_table[] = {
|
||||
+ { .compatible = "amcc,usb-otg-405ex", .data = ¶ms_amcc_dwc_otg },
|
||||
{ .compatible = "brcm,bcm2835-usb", .data = ¶ms_bcm2835 },
|
||||
{ .compatible = "rockchip,rk3066-usb", .data = ¶ms_rk3066 },
|
||||
{ .compatible = "snps,dwc2", .data = NULL },
|
File diff suppressed because it is too large
Load Diff
|
@ -1,292 +0,0 @@
|
|||
From: Wei Ni <wni@nvidia.com>
|
||||
Subject: hwmon: lm90: split set and show temp as common codes
|
||||
|
||||
Split set and show temp codes as common functions, so we can use
|
||||
it directly when implement linux thermal framework.
|
||||
And handle error return value for the lm90_select_remote_channel
|
||||
and write_tempx, then set_temp8 and set_temp11 could return it
|
||||
to user-space.
|
||||
|
||||
Discussed in:
|
||||
http://www.spinics.net/lists/linux-tegra/msg14020.html .
|
||||
Applied with Jean.
|
||||
|
||||
BUG=chrome-os-partner:30834
|
||||
TEST=None
|
||||
|
||||
Signed-off-by: Wei Ni <wni@nvidia.com>
|
||||
Signed-off-by: Jean Delvare <khali@linux-fr.org>
|
||||
Reviewed-on: https://chromium-review.googlesource.com/175114
|
||||
Tested-by: Wei Ni <wni.nvidia@gmail.com>
|
||||
Commit-Queue: Dylan Reid <dgreid@chromium.org>
|
||||
Reviewed-by: Dylan Reid <dgreid@chromium.org>
|
||||
(cherry picked from commit 614a96decdc7a3784128c9f21c5471367e2c627d)
|
||||
Change-Id: Idbe3948812c6737cba94810cd147c29cc527c3cf
|
||||
Reviewed-on: https://chromium-review.googlesource.com/212413
|
||||
Reviewed-by: Olof Johansson <olofj@chromium.org>
|
||||
Commit-Queue: Olof Johansson <olofj@chromium.org>
|
||||
---
|
||||
--- a/drivers/hwmon/lm90.c
|
||||
+++ b/drivers/hwmon/lm90.c
|
||||
@@ -473,20 +473,29 @@ static int lm90_read16(struct i2c_client
|
||||
* various registers have different meanings as a result of selecting a
|
||||
* non-default remote channel.
|
||||
*/
|
||||
-static inline void lm90_select_remote_channel(struct i2c_client *client,
|
||||
- struct lm90_data *data,
|
||||
- int channel)
|
||||
+static inline int lm90_select_remote_channel(struct i2c_client *client,
|
||||
+ struct lm90_data *data,
|
||||
+ int channel)
|
||||
{
|
||||
u8 config;
|
||||
+ int err;
|
||||
|
||||
if (data->kind == max6696) {
|
||||
lm90_read_reg(client, LM90_REG_R_CONFIG1, &config);
|
||||
config &= ~0x08;
|
||||
if (channel)
|
||||
config |= 0x08;
|
||||
- i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1,
|
||||
- config);
|
||||
+ err = i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1,
|
||||
+ config);
|
||||
+ if (err < 0) {
|
||||
+ dev_err(&client->dev,
|
||||
+ "Failed to select remote channel %d, err %d\n",
|
||||
+ channel, err);
|
||||
+ return err;
|
||||
+ }
|
||||
}
|
||||
+
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -759,29 +768,34 @@ static u16 temp_to_u16_adt7461(struct lm
|
||||
* Sysfs stuff
|
||||
*/
|
||||
|
||||
-static ssize_t show_temp8(struct device *dev, struct device_attribute *devattr,
|
||||
- char *buf)
|
||||
+static int read_temp8(struct device *dev, int index)
|
||||
{
|
||||
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct lm90_data *data = lm90_update_device(dev);
|
||||
int temp;
|
||||
|
||||
if (data->kind == adt7461 || data->kind == tmp451)
|
||||
- temp = temp_from_u8_adt7461(data, data->temp8[attr->index]);
|
||||
+ temp = temp_from_u8_adt7461(data, data->temp8[index]);
|
||||
else if (data->kind == max6646)
|
||||
- temp = temp_from_u8(data->temp8[attr->index]);
|
||||
+ temp = temp_from_u8(data->temp8[index]);
|
||||
else
|
||||
- temp = temp_from_s8(data->temp8[attr->index]);
|
||||
+ temp = temp_from_s8(data->temp8[index]);
|
||||
|
||||
/* +16 degrees offset for temp2 for the LM99 */
|
||||
- if (data->kind == lm99 && attr->index == 3)
|
||||
+ if (data->kind == lm99 && index == 3)
|
||||
temp += 16000;
|
||||
|
||||
- return sprintf(buf, "%d\n", temp);
|
||||
+ return temp;
|
||||
}
|
||||
|
||||
-static ssize_t set_temp8(struct device *dev, struct device_attribute *devattr,
|
||||
- const char *buf, size_t count)
|
||||
+static ssize_t show_temp8(struct device *dev, struct device_attribute *devattr,
|
||||
+ char *buf)
|
||||
+{
|
||||
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
+
|
||||
+ return sprintf(buf, "%d\n", read_temp8(dev, attr->index));
|
||||
+}
|
||||
+
|
||||
+static int write_temp8(struct device *dev, int index, long val)
|
||||
{
|
||||
static const u8 reg[TEMP8_REG_NUM] = {
|
||||
LM90_REG_W_LOCAL_LOW,
|
||||
@@ -794,60 +808,79 @@ static ssize_t set_temp8(struct device *
|
||||
MAX6659_REG_W_REMOTE_EMERG,
|
||||
};
|
||||
|
||||
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct lm90_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
- int nr = attr->index;
|
||||
- long val;
|
||||
int err;
|
||||
|
||||
- err = kstrtol(buf, 10, &val);
|
||||
- if (err < 0)
|
||||
- return err;
|
||||
-
|
||||
/* +16 degrees offset for temp2 for the LM99 */
|
||||
- if (data->kind == lm99 && attr->index == 3)
|
||||
+ if (data->kind == lm99 && index == 3)
|
||||
val -= 16000;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
if (data->kind == adt7461 || data->kind == tmp451)
|
||||
- data->temp8[nr] = temp_to_u8_adt7461(data, val);
|
||||
+ data->temp8[index] = temp_to_u8_adt7461(data, val);
|
||||
else if (data->kind == max6646)
|
||||
- data->temp8[nr] = temp_to_u8(val);
|
||||
+ data->temp8[index] = temp_to_u8(val);
|
||||
else
|
||||
- data->temp8[nr] = temp_to_s8(val);
|
||||
-
|
||||
- lm90_select_remote_channel(client, data, nr >= 6);
|
||||
- i2c_smbus_write_byte_data(client, reg[nr], data->temp8[nr]);
|
||||
- lm90_select_remote_channel(client, data, 0);
|
||||
+ data->temp8[index] = temp_to_s8(val);
|
||||
|
||||
+ if ((err = lm90_select_remote_channel(client, data, index >= 6)) ||
|
||||
+ (err = i2c_smbus_write_byte_data(client, reg[index],
|
||||
+ data->temp8[index])) ||
|
||||
+ (err = lm90_select_remote_channel(client, data, 0)))
|
||||
+ dev_err(dev, "write_temp8 failed, err %d\n", err);
|
||||
mutex_unlock(&data->update_lock);
|
||||
+
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+static ssize_t set_temp8(struct device *dev, struct device_attribute *devattr,
|
||||
+ const char *buf, size_t count)
|
||||
+{
|
||||
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
+ int index = attr->index;
|
||||
+ long val;
|
||||
+ int err;
|
||||
+
|
||||
+ err = kstrtol(buf, 10, &val);
|
||||
+ if (err < 0)
|
||||
+ return err;
|
||||
+
|
||||
+ err = write_temp8(dev, index, val);
|
||||
+ if (err < 0)
|
||||
+ return err;
|
||||
+
|
||||
return count;
|
||||
}
|
||||
|
||||
-static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr,
|
||||
- char *buf)
|
||||
+static int read_temp11(struct device *dev, int index)
|
||||
{
|
||||
- struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
|
||||
struct lm90_data *data = lm90_update_device(dev);
|
||||
int temp;
|
||||
|
||||
if (data->kind == adt7461 || data->kind == tmp451)
|
||||
- temp = temp_from_u16_adt7461(data, data->temp11[attr->index]);
|
||||
+ temp = temp_from_u16_adt7461(data, data->temp11[index]);
|
||||
else if (data->kind == max6646)
|
||||
- temp = temp_from_u16(data->temp11[attr->index]);
|
||||
+ temp = temp_from_u16(data->temp11[index]);
|
||||
else
|
||||
- temp = temp_from_s16(data->temp11[attr->index]);
|
||||
+ temp = temp_from_s16(data->temp11[index]);
|
||||
|
||||
/* +16 degrees offset for temp2 for the LM99 */
|
||||
- if (data->kind == lm99 && attr->index <= 2)
|
||||
+ if (data->kind == lm99 && index <= 2)
|
||||
temp += 16000;
|
||||
|
||||
- return sprintf(buf, "%d\n", temp);
|
||||
+ return temp;
|
||||
}
|
||||
|
||||
-static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr,
|
||||
- const char *buf, size_t count)
|
||||
+static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr,
|
||||
+ char *buf)
|
||||
+{
|
||||
+ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
|
||||
+
|
||||
+ return sprintf(buf, "%d\n", read_temp11(dev, attr->index));
|
||||
+}
|
||||
+
|
||||
+static int write_temp11(struct device *dev, int nr, int index, long val)
|
||||
{
|
||||
struct {
|
||||
u8 high;
|
||||
@@ -861,18 +894,10 @@ static ssize_t set_temp11(struct device
|
||||
{ LM90_REG_W_REMOTE_HIGHH, LM90_REG_W_REMOTE_HIGHL, 1 }
|
||||
};
|
||||
|
||||
- struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
|
||||
struct lm90_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
- int nr = attr->nr;
|
||||
- int index = attr->index;
|
||||
- long val;
|
||||
int err;
|
||||
|
||||
- err = kstrtol(buf, 10, &val);
|
||||
- if (err < 0)
|
||||
- return err;
|
||||
-
|
||||
/* +16 degrees offset for temp2 for the LM99 */
|
||||
if (data->kind == lm99 && index <= 2)
|
||||
val -= 16000;
|
||||
@@ -887,15 +912,50 @@ static ssize_t set_temp11(struct device
|
||||
else
|
||||
data->temp11[index] = temp_to_s8(val) << 8;
|
||||
|
||||
- lm90_select_remote_channel(client, data, reg[nr].channel);
|
||||
- i2c_smbus_write_byte_data(client, reg[nr].high,
|
||||
- data->temp11[index] >> 8);
|
||||
- if (data->flags & LM90_HAVE_REM_LIMIT_EXT)
|
||||
- i2c_smbus_write_byte_data(client, reg[nr].low,
|
||||
- data->temp11[index] & 0xff);
|
||||
- lm90_select_remote_channel(client, data, 0);
|
||||
+ err = lm90_select_remote_channel(client, data, reg[nr].channel);
|
||||
+ if (err)
|
||||
+ goto error;
|
||||
+
|
||||
+ err = i2c_smbus_write_byte_data(client, reg[nr].high,
|
||||
+ data->temp11[index] >> 8);
|
||||
+ if (err)
|
||||
+ goto error;
|
||||
+
|
||||
+ if (data->flags & LM90_HAVE_REM_LIMIT_EXT) {
|
||||
+ err = i2c_smbus_write_byte_data(client, reg[nr].low,
|
||||
+ data->temp11[index] & 0xff);
|
||||
+ if (err)
|
||||
+ goto error;
|
||||
+ }
|
||||
+
|
||||
+ err = lm90_select_remote_channel(client, data, 0);
|
||||
+
|
||||
+error:
|
||||
+ if (err)
|
||||
+ dev_err(dev, "write_temp11 failed, err %d\n", err);
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
+
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr,
|
||||
+ const char *buf, size_t count)
|
||||
+{
|
||||
+ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
|
||||
+ int nr = attr->nr;
|
||||
+ int index = attr->index;
|
||||
+ long val;
|
||||
+ int err;
|
||||
+
|
||||
+ err = kstrtol(buf, 10, &val);
|
||||
+ if (err < 0)
|
||||
+ return err;
|
||||
+
|
||||
+ err = write_temp11(dev, nr, index, val);
|
||||
+ if (err < 0)
|
||||
+ return err;
|
||||
+
|
||||
return count;
|
||||
}
|
||||
|
|
@ -1,149 +0,0 @@
|
|||
From: Wei Ni <wni@nvidia.com>
|
||||
Subject: hwmon: lm90: expose to thermal fw via DT nodes
|
||||
|
||||
This patch adds to lm90 temperature sensor the possibility
|
||||
to expose itself as thermal zone device, registered on the
|
||||
thermal framework.
|
||||
|
||||
The thermal zone is built only if a device tree node
|
||||
describing a thermal zone for this sensor is present
|
||||
inside the lm90 DT node. Otherwise, the driver behavior
|
||||
will be the same.
|
||||
|
||||
Discussed in:
|
||||
http://www.gossamer-threads.com/lists/linux/kernel/1992853
|
||||
|
||||
BUG=chrome-os-partner:30834
|
||||
TEST=Verified. Build and boot up system.
|
||||
|
||||
Signed-off-by: Wei Ni <wni@nvidia.com>
|
||||
Reviewed-on: https://chromium-review.googlesource.com/181447
|
||||
Reviewed-by: Dylan Reid <dgreid@chromium.org>
|
||||
Tested-by: Dylan Reid <dgreid@chromium.org>
|
||||
Commit-Queue: Dylan Reid <dgreid@chromium.org>
|
||||
Change-Id: Id356b94d7e8f4b49ec15e46b17a1fa2ff0cbf8cf
|
||||
Reviewed-on: https://chromium-review.googlesource.com/212414
|
||||
Tested-by: Wei Ni <wni.nvidia@gmail.com>
|
||||
Reviewed-by: Olof Johansson <olofj@chromium.org>
|
||||
Commit-Queue: Olof Johansson <olofj@chromium.org>
|
||||
---
|
||||
--- a/drivers/hwmon/lm90.c
|
||||
+++ b/drivers/hwmon/lm90.c
|
||||
@@ -96,6 +96,8 @@
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/thermal.h>
|
||||
|
||||
/*
|
||||
* Addresses to scan
|
||||
@@ -119,6 +121,13 @@ static const unsigned short normal_i2c[]
|
||||
enum chips { lm90, adm1032, lm99, lm86, max6657, max6659, adt7461, max6680,
|
||||
max6646, w83l771, max6696, sa56004, g781, tmp451 };
|
||||
|
||||
+enum sensor_id {
|
||||
+ LOCAL = 0,
|
||||
+ REMOTE,
|
||||
+ REMOTE2,
|
||||
+ SENSOR_ID_END,
|
||||
+};
|
||||
+
|
||||
/*
|
||||
* The LM90 registers
|
||||
*/
|
||||
@@ -368,6 +377,7 @@ struct lm90_data {
|
||||
struct i2c_client *client;
|
||||
struct device *hwmon_dev;
|
||||
const struct attribute_group *groups[6];
|
||||
+ struct thermal_zone_device *tz[SENSOR_ID_END];
|
||||
struct mutex update_lock;
|
||||
struct regulator *regulator;
|
||||
char valid; /* zero until following fields are valid */
|
||||
@@ -880,6 +890,24 @@ static ssize_t show_temp11(struct device
|
||||
return sprintf(buf, "%d\n", read_temp11(dev, attr->index));
|
||||
}
|
||||
|
||||
+static int lm90_read_local_temp(void *dev, int *temp)
|
||||
+{
|
||||
+ *temp = read_temp11(dev, 4);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int lm90_read_remote_temp(void *dev, int *temp)
|
||||
+{
|
||||
+ *temp = read_temp11(dev, 0);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int lm90_read_remote2_temp(void *dev, int *temp)
|
||||
+{
|
||||
+ *temp = read_temp11(dev, 5);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static int write_temp11(struct device *dev, int nr, int index, long val)
|
||||
{
|
||||
struct {
|
||||
@@ -1210,6 +1238,18 @@ static const struct attribute_group lm90
|
||||
.attrs = lm90_temp3_attributes,
|
||||
};
|
||||
|
||||
+static const struct thermal_zone_of_device_ops local_temp_sensor = {
|
||||
+ .get_temp = lm90_read_local_temp,
|
||||
+};
|
||||
+
|
||||
+static const struct thermal_zone_of_device_ops remote_temp_sensor = {
|
||||
+ .get_temp = lm90_read_remote_temp,
|
||||
+};
|
||||
+
|
||||
+static const struct thermal_zone_of_device_ops remote2_temp_sensor = {
|
||||
+ .get_temp = lm90_read_remote2_temp,
|
||||
+};
|
||||
+
|
||||
/* pec used for ADM1032 only */
|
||||
static ssize_t show_pec(struct device *dev, struct device_attribute *dummy,
|
||||
char *buf)
|
||||
@@ -1659,6 +1699,30 @@ static int lm90_probe(struct i2c_client
|
||||
}
|
||||
}
|
||||
|
||||
+ data->tz[LOCAL] = thermal_zone_of_sensor_register(&client->dev,
|
||||
+ LOCAL,
|
||||
+ &client->dev,
|
||||
+ &local_temp_sensor);
|
||||
+ if (IS_ERR(data->tz[LOCAL]))
|
||||
+ data->tz[LOCAL] = NULL;
|
||||
+
|
||||
+ data->tz[REMOTE] = thermal_zone_of_sensor_register(&client->dev,
|
||||
+ REMOTE,
|
||||
+ &client->dev,
|
||||
+ &remote_temp_sensor);
|
||||
+ if (IS_ERR(data->tz[REMOTE]))
|
||||
+ data->tz[REMOTE] = NULL;
|
||||
+
|
||||
+ if (data->flags & LM90_HAVE_TEMP3) {
|
||||
+ data->tz[REMOTE2] = thermal_zone_of_sensor_register(
|
||||
+ &client->dev,
|
||||
+ REMOTE2,
|
||||
+ &client->dev,
|
||||
+ &remote2_temp_sensor);
|
||||
+ if (IS_ERR(data->tz[REMOTE2]))
|
||||
+ data->tz[REMOTE2] = NULL;
|
||||
+ }
|
||||
+
|
||||
return 0;
|
||||
|
||||
exit_unregister:
|
||||
@@ -1674,8 +1738,11 @@ exit_restore:
|
||||
|
||||
static int lm90_remove(struct i2c_client *client)
|
||||
{
|
||||
+ int i;
|
||||
struct lm90_data *data = i2c_get_clientdata(client);
|
||||
|
||||
+ for (i = 0; i < SENSOR_ID_END; i++)
|
||||
+ thermal_zone_of_sensor_unregister(&client->dev, data->tz[i]);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
device_remove_file(&client->dev, &dev_attr_pec);
|
||||
lm90_restore_conf(client, data);
|
Loading…
Reference in New Issue