Revert "mvebu: remove linux 4.4 support"
This reverts commit 51397d7d95.
There are some unresolved random crashes on WRT1900AC v1 that still need
to be sorted out
Signed-off-by: Felix Fietkau <nbd@nbd.name>
			
			
This commit is contained in:
		
							
								
								
									
										437
									
								
								target/linux/mvebu/config-4.4
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										437
									
								
								target/linux/mvebu/config-4.4
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,437 @@
 | 
			
		||||
CONFIG_AHCI_MVEBU=y
 | 
			
		||||
CONFIG_ALIGNMENT_TRAP=y
 | 
			
		||||
CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
 | 
			
		||||
CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
 | 
			
		||||
CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y
 | 
			
		||||
CONFIG_ARCH_HAS_SG_CHAIN=y
 | 
			
		||||
CONFIG_ARCH_HAS_TICK_BROADCAST=y
 | 
			
		||||
CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
 | 
			
		||||
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
 | 
			
		||||
CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
 | 
			
		||||
CONFIG_ARCH_MULTIPLATFORM=y
 | 
			
		||||
# CONFIG_ARCH_MULTI_CPU_AUTO is not set
 | 
			
		||||
CONFIG_ARCH_MULTI_V6_V7=y
 | 
			
		||||
CONFIG_ARCH_MULTI_V7=y
 | 
			
		||||
CONFIG_ARCH_MVEBU=y
 | 
			
		||||
CONFIG_ARCH_NR_GPIO=0
 | 
			
		||||
CONFIG_ARCH_REQUIRE_GPIOLIB=y
 | 
			
		||||
# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
 | 
			
		||||
# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
 | 
			
		||||
CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y
 | 
			
		||||
CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y
 | 
			
		||||
CONFIG_ARCH_SUPPORTS_UPROBES=y
 | 
			
		||||
CONFIG_ARCH_SUSPEND_POSSIBLE=y
 | 
			
		||||
CONFIG_ARCH_USE_BUILTIN_BSWAP=y
 | 
			
		||||
CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
 | 
			
		||||
CONFIG_ARCH_WANT_GENERAL_HUGETLB=y
 | 
			
		||||
CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
 | 
			
		||||
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
 | 
			
		||||
CONFIG_ARM=y
 | 
			
		||||
CONFIG_ARMADA_370_CLK=y
 | 
			
		||||
CONFIG_ARMADA_370_XP_TIMER=y
 | 
			
		||||
CONFIG_ARMADA_38X_CLK=y
 | 
			
		||||
CONFIG_ARMADA_THERMAL=y
 | 
			
		||||
CONFIG_ARMADA_XP_CLK=y
 | 
			
		||||
CONFIG_ARM_APPENDED_DTB=y
 | 
			
		||||
CONFIG_ARM_ATAG_DTB_COMPAT=y
 | 
			
		||||
# CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEND is not set
 | 
			
		||||
CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_FROM_BOOTLOADER=y
 | 
			
		||||
CONFIG_ARM_CPU_SUSPEND=y
 | 
			
		||||
CONFIG_ARM_CRYPTO=y
 | 
			
		||||
CONFIG_ARM_ERRATA_720789=y
 | 
			
		||||
CONFIG_ARM_GIC=y
 | 
			
		||||
CONFIG_ARM_HAS_SG_CHAIN=y
 | 
			
		||||
CONFIG_ARM_HEAVY_MB=y
 | 
			
		||||
CONFIG_ARM_L1_CACHE_SHIFT=6
 | 
			
		||||
CONFIG_ARM_L1_CACHE_SHIFT_6=y
 | 
			
		||||
# CONFIG_ARM_LPAE is not set
 | 
			
		||||
CONFIG_ARM_MVEBU_V7_CPUIDLE=y
 | 
			
		||||
CONFIG_ARM_PATCH_PHYS_VIRT=y
 | 
			
		||||
CONFIG_ARM_THUMB=y
 | 
			
		||||
# CONFIG_ARM_THUMBEE is not set
 | 
			
		||||
CONFIG_ARM_UNWIND=y
 | 
			
		||||
CONFIG_ARM_VIRT_EXT=y
 | 
			
		||||
CONFIG_ASYNC_TX_ENABLE_CHANNEL_SWITCH=y
 | 
			
		||||
CONFIG_ATA=y
 | 
			
		||||
CONFIG_ATAGS=y
 | 
			
		||||
CONFIG_AUTO_ZRELADDR=y
 | 
			
		||||
CONFIG_BLK_DEV_LOOP=y
 | 
			
		||||
CONFIG_BOUNCE=y
 | 
			
		||||
# CONFIG_CACHE_FEROCEON_L2 is not set
 | 
			
		||||
CONFIG_CACHE_L2X0=y
 | 
			
		||||
CONFIG_CLKDEV_LOOKUP=y
 | 
			
		||||
CONFIG_CLKSRC_MMIO=y
 | 
			
		||||
CONFIG_CLKSRC_OF=y
 | 
			
		||||
CONFIG_CLKSRC_PROBE=y
 | 
			
		||||
CONFIG_CLONE_BACKWARDS=y
 | 
			
		||||
CONFIG_COMMON_CLK=y
 | 
			
		||||
CONFIG_CPUFREQ_DT=y
 | 
			
		||||
CONFIG_CPU_32v6K=y
 | 
			
		||||
CONFIG_CPU_32v7=y
 | 
			
		||||
CONFIG_CPU_ABRT_EV7=y
 | 
			
		||||
# CONFIG_CPU_BIG_ENDIAN is not set
 | 
			
		||||
# CONFIG_CPU_BPREDICT_DISABLE is not set
 | 
			
		||||
CONFIG_CPU_CACHE_V7=y
 | 
			
		||||
CONFIG_CPU_CACHE_VIPT=y
 | 
			
		||||
CONFIG_CPU_COPY_V6=y
 | 
			
		||||
CONFIG_CPU_CP15=y
 | 
			
		||||
CONFIG_CPU_CP15_MMU=y
 | 
			
		||||
CONFIG_CPU_FREQ=y
 | 
			
		||||
CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
 | 
			
		||||
# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
 | 
			
		||||
CONFIG_CPU_FREQ_GOV_COMMON=y
 | 
			
		||||
# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
 | 
			
		||||
CONFIG_CPU_FREQ_GOV_ONDEMAND=y
 | 
			
		||||
CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
 | 
			
		||||
# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
 | 
			
		||||
# CONFIG_CPU_FREQ_GOV_USERSPACE is not set
 | 
			
		||||
CONFIG_CPU_FREQ_STAT=y
 | 
			
		||||
CONFIG_CPU_HAS_ASID=y
 | 
			
		||||
# CONFIG_CPU_ICACHE_DISABLE is not set
 | 
			
		||||
CONFIG_CPU_IDLE=y
 | 
			
		||||
CONFIG_CPU_IDLE_GOV_LADDER=y
 | 
			
		||||
CONFIG_CPU_PABRT_V7=y
 | 
			
		||||
CONFIG_CPU_PJ4B=y
 | 
			
		||||
CONFIG_CPU_PM=y
 | 
			
		||||
CONFIG_CPU_RMAP=y
 | 
			
		||||
CONFIG_CPU_THERMAL=y
 | 
			
		||||
CONFIG_CPU_TLB_V7=y
 | 
			
		||||
CONFIG_CPU_V7=y
 | 
			
		||||
CONFIG_CRC16=y
 | 
			
		||||
CONFIG_CRYPTO_ABLK_HELPER=y
 | 
			
		||||
CONFIG_CRYPTO_AEAD=y
 | 
			
		||||
CONFIG_CRYPTO_AEAD2=y
 | 
			
		||||
CONFIG_CRYPTO_AES_ARM=y
 | 
			
		||||
CONFIG_CRYPTO_AES_ARM_BS=y
 | 
			
		||||
# CONFIG_CRYPTO_AES_ARM_CE is not set
 | 
			
		||||
CONFIG_CRYPTO_CRC32C=y
 | 
			
		||||
CONFIG_CRYPTO_CRYPTD=y
 | 
			
		||||
CONFIG_CRYPTO_DEFLATE=y
 | 
			
		||||
CONFIG_CRYPTO_DES=y
 | 
			
		||||
CONFIG_CRYPTO_DEV_MARVELL_CESA=y
 | 
			
		||||
# CONFIG_CRYPTO_GHASH_ARM_CE is not set
 | 
			
		||||
CONFIG_CRYPTO_HASH=y
 | 
			
		||||
CONFIG_CRYPTO_HASH2=y
 | 
			
		||||
CONFIG_CRYPTO_HW=y
 | 
			
		||||
CONFIG_CRYPTO_LZO=y
 | 
			
		||||
CONFIG_CRYPTO_MANAGER=y
 | 
			
		||||
CONFIG_CRYPTO_MANAGER2=y
 | 
			
		||||
CONFIG_CRYPTO_NULL2=y
 | 
			
		||||
CONFIG_CRYPTO_RNG2=y
 | 
			
		||||
CONFIG_CRYPTO_SHA1=y
 | 
			
		||||
CONFIG_CRYPTO_SHA1_ARM=y
 | 
			
		||||
# CONFIG_CRYPTO_SHA1_ARM_CE is not set
 | 
			
		||||
CONFIG_CRYPTO_SHA1_ARM_NEON=y
 | 
			
		||||
CONFIG_CRYPTO_SHA256_ARM=y
 | 
			
		||||
# CONFIG_CRYPTO_SHA2_ARM_CE is not set
 | 
			
		||||
CONFIG_CRYPTO_SHA512_ARM=y
 | 
			
		||||
CONFIG_CRYPTO_WORKQUEUE=y
 | 
			
		||||
CONFIG_DCACHE_WORD_ACCESS=y
 | 
			
		||||
CONFIG_DEBUG_INFO=y
 | 
			
		||||
CONFIG_DEBUG_LL=y
 | 
			
		||||
CONFIG_DEBUG_LL_INCLUDE="debug/8250.S"
 | 
			
		||||
CONFIG_DEBUG_MVEBU_UART0=y
 | 
			
		||||
# CONFIG_DEBUG_MVEBU_UART0_ALTERNATE is not set
 | 
			
		||||
# CONFIG_DEBUG_MVEBU_UART1_ALTERNATE is not set
 | 
			
		||||
CONFIG_DEBUG_UART_8250=y
 | 
			
		||||
# CONFIG_DEBUG_UART_8250_FLOW_CONTROL is not set
 | 
			
		||||
CONFIG_DEBUG_UART_8250_SHIFT=2
 | 
			
		||||
# CONFIG_DEBUG_UART_8250_WORD is not set
 | 
			
		||||
CONFIG_DEBUG_UART_PHYS=0xd0012000
 | 
			
		||||
CONFIG_DEBUG_UART_VIRT=0xfec12000
 | 
			
		||||
CONFIG_DEBUG_UNCOMPRESS=y
 | 
			
		||||
CONFIG_DEBUG_USER=y
 | 
			
		||||
CONFIG_DMADEVICES=y
 | 
			
		||||
CONFIG_DMA_ENGINE=y
 | 
			
		||||
CONFIG_DMA_ENGINE_RAID=y
 | 
			
		||||
CONFIG_DMA_OF=y
 | 
			
		||||
CONFIG_DTC=y
 | 
			
		||||
# CONFIG_DW_DMAC_PCI is not set
 | 
			
		||||
CONFIG_EARLY_PRINTK=y
 | 
			
		||||
CONFIG_EDAC_ATOMIC_SCRUB=y
 | 
			
		||||
CONFIG_EDAC_SUPPORT=y
 | 
			
		||||
CONFIG_EXT4_FS=y
 | 
			
		||||
# CONFIG_F2FS_CHECK_FS is not set
 | 
			
		||||
CONFIG_F2FS_FS=y
 | 
			
		||||
# CONFIG_F2FS_FS_SECURITY is not set
 | 
			
		||||
CONFIG_F2FS_FS_XATTR=y
 | 
			
		||||
CONFIG_F2FS_STAT_FS=y
 | 
			
		||||
CONFIG_FIXED_PHY=y
 | 
			
		||||
CONFIG_FIX_EARLYCON_MEM=y
 | 
			
		||||
CONFIG_FS_MBCACHE=y
 | 
			
		||||
CONFIG_GENERIC_ALLOCATOR=y
 | 
			
		||||
CONFIG_GENERIC_BUG=y
 | 
			
		||||
CONFIG_GENERIC_CLOCKEVENTS=y
 | 
			
		||||
CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
 | 
			
		||||
CONFIG_GENERIC_IDLE_POLL_SETUP=y
 | 
			
		||||
CONFIG_GENERIC_IO=y
 | 
			
		||||
CONFIG_GENERIC_IRQ_CHIP=y
 | 
			
		||||
CONFIG_GENERIC_IRQ_SHOW=y
 | 
			
		||||
CONFIG_GENERIC_IRQ_SHOW_LEVEL=y
 | 
			
		||||
CONFIG_GENERIC_PCI_IOMAP=y
 | 
			
		||||
CONFIG_GENERIC_PHY=y
 | 
			
		||||
CONFIG_GENERIC_SCHED_CLOCK=y
 | 
			
		||||
CONFIG_GENERIC_SMP_IDLE_THREAD=y
 | 
			
		||||
CONFIG_GENERIC_STRNCPY_FROM_USER=y
 | 
			
		||||
CONFIG_GENERIC_STRNLEN_USER=y
 | 
			
		||||
CONFIG_GLOB=y
 | 
			
		||||
CONFIG_GPIOLIB=y
 | 
			
		||||
CONFIG_GPIO_DEVRES=y
 | 
			
		||||
CONFIG_GPIO_MVEBU=y
 | 
			
		||||
CONFIG_GPIO_MVEBU_PWM=y
 | 
			
		||||
CONFIG_GPIO_PCA953X=y
 | 
			
		||||
# CONFIG_GPIO_PCA953X_IRQ is not set
 | 
			
		||||
CONFIG_GPIO_SYSFS=y
 | 
			
		||||
CONFIG_HANDLE_DOMAIN_IRQ=y
 | 
			
		||||
CONFIG_HARDIRQS_SW_RESEND=y
 | 
			
		||||
CONFIG_HAS_DMA=y
 | 
			
		||||
CONFIG_HAS_IOMEM=y
 | 
			
		||||
CONFIG_HAS_IOPORT_MAP=y
 | 
			
		||||
# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
 | 
			
		||||
CONFIG_HAVE_ARCH_AUDITSYSCALL=y
 | 
			
		||||
CONFIG_HAVE_ARCH_BITREVERSE=y
 | 
			
		||||
CONFIG_HAVE_ARCH_JUMP_LABEL=y
 | 
			
		||||
CONFIG_HAVE_ARCH_KGDB=y
 | 
			
		||||
CONFIG_HAVE_ARCH_PFN_VALID=y
 | 
			
		||||
CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
 | 
			
		||||
CONFIG_HAVE_ARCH_TRACEHOOK=y
 | 
			
		||||
CONFIG_HAVE_ARM_SCU=y
 | 
			
		||||
CONFIG_HAVE_ARM_TWD=y
 | 
			
		||||
# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
 | 
			
		||||
CONFIG_HAVE_BPF_JIT=y
 | 
			
		||||
CONFIG_HAVE_CC_STACKPROTECTOR=y
 | 
			
		||||
CONFIG_HAVE_CLK=y
 | 
			
		||||
CONFIG_HAVE_CLK_PREPARE=y
 | 
			
		||||
CONFIG_HAVE_CONTEXT_TRACKING=y
 | 
			
		||||
CONFIG_HAVE_C_RECORDMCOUNT=y
 | 
			
		||||
CONFIG_HAVE_DEBUG_KMEMLEAK=y
 | 
			
		||||
CONFIG_HAVE_DMA_API_DEBUG=y
 | 
			
		||||
CONFIG_HAVE_DMA_ATTRS=y
 | 
			
		||||
CONFIG_HAVE_DMA_CONTIGUOUS=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=y
 | 
			
		||||
CONFIG_HAVE_IDE=y
 | 
			
		||||
CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
 | 
			
		||||
CONFIG_HAVE_MEMBLOCK=y
 | 
			
		||||
CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
 | 
			
		||||
CONFIG_HAVE_NET_DSA=y
 | 
			
		||||
CONFIG_HAVE_OPROFILE=y
 | 
			
		||||
CONFIG_HAVE_OPTPROBES=y
 | 
			
		||||
CONFIG_HAVE_PERF_EVENTS=y
 | 
			
		||||
CONFIG_HAVE_PERF_REGS=y
 | 
			
		||||
CONFIG_HAVE_PERF_USER_STACK_DUMP=y
 | 
			
		||||
CONFIG_HAVE_PROC_CPU=y
 | 
			
		||||
CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
 | 
			
		||||
CONFIG_HAVE_SMP=y
 | 
			
		||||
CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
 | 
			
		||||
CONFIG_HAVE_UID16=y
 | 
			
		||||
CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
 | 
			
		||||
CONFIG_HIGHMEM=y
 | 
			
		||||
# CONFIG_HIGHPTE is not set
 | 
			
		||||
CONFIG_HOTPLUG_CPU=y
 | 
			
		||||
CONFIG_HWBM=y
 | 
			
		||||
CONFIG_HWMON=y
 | 
			
		||||
CONFIG_HZ_FIXED=0
 | 
			
		||||
CONFIG_HZ_PERIODIC=y
 | 
			
		||||
CONFIG_I2C=y
 | 
			
		||||
CONFIG_I2C_BOARDINFO=y
 | 
			
		||||
CONFIG_I2C_CHARDEV=y
 | 
			
		||||
CONFIG_I2C_MV64XXX=y
 | 
			
		||||
CONFIG_INITRAMFS_SOURCE=""
 | 
			
		||||
CONFIG_IOMMU_HELPER=y
 | 
			
		||||
CONFIG_IRQCHIP=y
 | 
			
		||||
CONFIG_IRQ_DOMAIN=y
 | 
			
		||||
CONFIG_IRQ_DOMAIN_DEBUG=y
 | 
			
		||||
CONFIG_IRQ_DOMAIN_HIERARCHY=y
 | 
			
		||||
CONFIG_IRQ_FORCED_THREADING=y
 | 
			
		||||
CONFIG_IRQ_WORK=y
 | 
			
		||||
# CONFIG_IWMMXT is not set
 | 
			
		||||
CONFIG_JBD2=y
 | 
			
		||||
CONFIG_LEDS_GPIO=y
 | 
			
		||||
CONFIG_LEDS_PCA963X=y
 | 
			
		||||
CONFIG_LEDS_TLC591XX=y
 | 
			
		||||
CONFIG_LIBFDT=y
 | 
			
		||||
CONFIG_LOCK_SPIN_ON_OWNER=y
 | 
			
		||||
CONFIG_LZO_COMPRESS=y
 | 
			
		||||
CONFIG_LZO_DECOMPRESS=y
 | 
			
		||||
CONFIG_MACH_ARMADA_370=y
 | 
			
		||||
# CONFIG_MACH_ARMADA_375 is not set
 | 
			
		||||
CONFIG_MACH_ARMADA_38X=y
 | 
			
		||||
# CONFIG_MACH_ARMADA_39X is not set
 | 
			
		||||
CONFIG_MACH_ARMADA_XP=y
 | 
			
		||||
# CONFIG_MACH_DOVE is not set
 | 
			
		||||
CONFIG_MACH_MVEBU_ANY=y
 | 
			
		||||
CONFIG_MACH_MVEBU_V7=y
 | 
			
		||||
CONFIG_MAGIC_SYSRQ=y
 | 
			
		||||
CONFIG_MANGLE_BOOTARGS=y
 | 
			
		||||
CONFIG_MARVELL_PHY=y
 | 
			
		||||
CONFIG_MDIO_BOARDINFO=y
 | 
			
		||||
CONFIG_MDIO_I2C=y
 | 
			
		||||
CONFIG_MEMORY=y
 | 
			
		||||
CONFIG_MIGHT_HAVE_CACHE_L2X0=y
 | 
			
		||||
CONFIG_MIGHT_HAVE_PCI=y
 | 
			
		||||
CONFIG_MMC=y
 | 
			
		||||
CONFIG_MMC_BLOCK=y
 | 
			
		||||
CONFIG_MMC_MVSDIO=y
 | 
			
		||||
CONFIG_MMC_SDHCI=y
 | 
			
		||||
# CONFIG_MMC_SDHCI_PCI is not set
 | 
			
		||||
CONFIG_MMC_SDHCI_PLTFM=y
 | 
			
		||||
CONFIG_MMC_SDHCI_PXAV3=y
 | 
			
		||||
# CONFIG_MMC_TIFM_SD is not set
 | 
			
		||||
CONFIG_MODULES_USE_ELF_REL=y
 | 
			
		||||
CONFIG_MTD_CFI_STAA=y
 | 
			
		||||
CONFIG_MTD_M25P80=y
 | 
			
		||||
CONFIG_MTD_NAND=y
 | 
			
		||||
CONFIG_MTD_NAND_ECC=y
 | 
			
		||||
CONFIG_MTD_NAND_PXA3xx=y
 | 
			
		||||
CONFIG_MTD_SPI_NOR=y
 | 
			
		||||
CONFIG_MTD_SPLIT_FIRMWARE=y
 | 
			
		||||
CONFIG_MTD_UBI=y
 | 
			
		||||
CONFIG_MTD_UBI_BEB_LIMIT=20
 | 
			
		||||
CONFIG_MTD_UBI_BLOCK=y
 | 
			
		||||
# CONFIG_MTD_UBI_FASTMAP is not set
 | 
			
		||||
# CONFIG_MTD_UBI_GLUEBI is not set
 | 
			
		||||
CONFIG_MTD_UBI_WL_THRESHOLD=4096
 | 
			
		||||
CONFIG_MULTI_IRQ_HANDLER=y
 | 
			
		||||
CONFIG_MUTEX_SPIN_ON_OWNER=y
 | 
			
		||||
CONFIG_MVEBU_CLK_COMMON=y
 | 
			
		||||
CONFIG_MVEBU_CLK_COREDIV=y
 | 
			
		||||
CONFIG_MVEBU_CLK_CPU=y
 | 
			
		||||
CONFIG_MVEBU_DEVBUS=y
 | 
			
		||||
CONFIG_MVEBU_MBUS=y
 | 
			
		||||
CONFIG_MVMDIO=y
 | 
			
		||||
CONFIG_MVNETA=y
 | 
			
		||||
CONFIG_MVNETA_BM=y
 | 
			
		||||
CONFIG_MVSW61XX_PHY=y
 | 
			
		||||
CONFIG_MV_XOR=y
 | 
			
		||||
CONFIG_NEED_DMA_MAP_STATE=y
 | 
			
		||||
CONFIG_NEON=y
 | 
			
		||||
CONFIG_NET_FLOW_LIMIT=y
 | 
			
		||||
CONFIG_NLS=y
 | 
			
		||||
CONFIG_NOP_USB_XCEIV=y
 | 
			
		||||
CONFIG_NO_BOOTMEM=y
 | 
			
		||||
CONFIG_NR_CPUS=4
 | 
			
		||||
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_SIGSUSPEND3=y
 | 
			
		||||
CONFIG_ORION_WATCHDOG=y
 | 
			
		||||
CONFIG_OUTER_CACHE=y
 | 
			
		||||
CONFIG_OUTER_CACHE_SYNC=y
 | 
			
		||||
CONFIG_PAGE_OFFSET=0xC0000000
 | 
			
		||||
CONFIG_PCI=y
 | 
			
		||||
# CONFIG_PCI_DOMAINS_GENERIC is not set
 | 
			
		||||
CONFIG_PCI_MVEBU=y
 | 
			
		||||
CONFIG_PERF_USE_VMALLOC=y
 | 
			
		||||
CONFIG_PGTABLE_LEVELS=2
 | 
			
		||||
CONFIG_PHYLIB=y
 | 
			
		||||
CONFIG_PHYLINK=y
 | 
			
		||||
CONFIG_PINCTRL=y
 | 
			
		||||
CONFIG_PINCTRL_ARMADA_370=y
 | 
			
		||||
CONFIG_PINCTRL_ARMADA_38X=y
 | 
			
		||||
CONFIG_PINCTRL_ARMADA_XP=y
 | 
			
		||||
CONFIG_PINCTRL_MVEBU=y
 | 
			
		||||
# CONFIG_PINCTRL_SINGLE is not set
 | 
			
		||||
CONFIG_PJ4B_ERRATA_4742=y
 | 
			
		||||
# CONFIG_PL310_ERRATA_588369 is not set
 | 
			
		||||
# CONFIG_PL310_ERRATA_727915 is not set
 | 
			
		||||
# CONFIG_PL310_ERRATA_753970 is not set
 | 
			
		||||
# CONFIG_PL310_ERRATA_769419 is not set
 | 
			
		||||
CONFIG_PLAT_ORION=y
 | 
			
		||||
CONFIG_PM_OPP=y
 | 
			
		||||
CONFIG_PWM=y
 | 
			
		||||
CONFIG_PWM_SYSFS=y
 | 
			
		||||
CONFIG_RATIONAL=y
 | 
			
		||||
CONFIG_RCU_STALL_COMMON=y
 | 
			
		||||
CONFIG_REGMAP=y
 | 
			
		||||
CONFIG_REGMAP_I2C=y
 | 
			
		||||
CONFIG_REGULATOR=y
 | 
			
		||||
CONFIG_REGULATOR_FIXED_VOLTAGE=y
 | 
			
		||||
CONFIG_RFS_ACCEL=y
 | 
			
		||||
CONFIG_RPS=y
 | 
			
		||||
CONFIG_RTC_CLASS=y
 | 
			
		||||
CONFIG_RTC_DRV_ARMADA38X=y
 | 
			
		||||
CONFIG_RTC_DRV_MV=y
 | 
			
		||||
CONFIG_RWSEM_SPIN_ON_OWNER=y
 | 
			
		||||
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
 | 
			
		||||
CONFIG_SATA_AHCI_PLATFORM=y
 | 
			
		||||
CONFIG_SATA_MV=y
 | 
			
		||||
CONFIG_SCHED_HRTICK=y
 | 
			
		||||
# CONFIG_SCHED_INFO is not set
 | 
			
		||||
CONFIG_SCSI=y
 | 
			
		||||
CONFIG_SENSORS_PWM_FAN=y
 | 
			
		||||
CONFIG_SENSORS_TMP421=y
 | 
			
		||||
CONFIG_SERIAL_8250_DW=y
 | 
			
		||||
CONFIG_SERIAL_8250_FSL=y
 | 
			
		||||
CONFIG_SFP=y
 | 
			
		||||
CONFIG_SMP=y
 | 
			
		||||
CONFIG_SMP_ON_UP=y
 | 
			
		||||
CONFIG_SOC_BUS=y
 | 
			
		||||
CONFIG_SPARSE_IRQ=y
 | 
			
		||||
CONFIG_SPI=y
 | 
			
		||||
CONFIG_SPI_MASTER=y
 | 
			
		||||
CONFIG_SPI_ORION=y
 | 
			
		||||
CONFIG_SRAM=y
 | 
			
		||||
CONFIG_SRCU=y
 | 
			
		||||
CONFIG_SWCONFIG=y
 | 
			
		||||
CONFIG_SWIOTLB=y
 | 
			
		||||
CONFIG_SWPHY=y
 | 
			
		||||
CONFIG_SWP_EMULATE=y
 | 
			
		||||
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
 | 
			
		||||
CONFIG_THERMAL=y
 | 
			
		||||
CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
 | 
			
		||||
CONFIG_THERMAL_GOV_STEP_WISE=y
 | 
			
		||||
CONFIG_THERMAL_HWMON=y
 | 
			
		||||
CONFIG_THERMAL_OF=y
 | 
			
		||||
# CONFIG_THUMB2_KERNEL is not set
 | 
			
		||||
CONFIG_TICK_CPU_ACCOUNTING=y
 | 
			
		||||
CONFIG_TIMER_STATS=y
 | 
			
		||||
CONFIG_TREE_RCU=y
 | 
			
		||||
CONFIG_UBIFS_FS=y
 | 
			
		||||
# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set
 | 
			
		||||
CONFIG_UBIFS_FS_LZO=y
 | 
			
		||||
CONFIG_UBIFS_FS_ZLIB=y
 | 
			
		||||
CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
 | 
			
		||||
CONFIG_USB=y
 | 
			
		||||
CONFIG_USB_COMMON=y
 | 
			
		||||
CONFIG_USB_EHCI_HCD=y
 | 
			
		||||
CONFIG_USB_EHCI_HCD_ORION=y
 | 
			
		||||
CONFIG_USB_EHCI_HCD_PLATFORM=y
 | 
			
		||||
CONFIG_USB_EHCI_PCI=y
 | 
			
		||||
CONFIG_USB_LEDS_TRIGGER_USBPORT=y
 | 
			
		||||
CONFIG_USB_PHY=y
 | 
			
		||||
CONFIG_USB_STORAGE=y
 | 
			
		||||
CONFIG_USB_SUPPORT=y
 | 
			
		||||
# CONFIG_USB_UHCI_HCD is not set
 | 
			
		||||
CONFIG_USB_XHCI_HCD=y
 | 
			
		||||
CONFIG_USB_XHCI_MVEBU=y
 | 
			
		||||
CONFIG_USB_XHCI_PCI=y
 | 
			
		||||
CONFIG_USB_XHCI_PLATFORM=y
 | 
			
		||||
CONFIG_USE_OF=y
 | 
			
		||||
CONFIG_VECTORS_BASE=0xffff0000
 | 
			
		||||
CONFIG_VFP=y
 | 
			
		||||
CONFIG_VFPv3=y
 | 
			
		||||
CONFIG_WATCHDOG_CORE=y
 | 
			
		||||
CONFIG_XPS=y
 | 
			
		||||
CONFIG_XZ_DEC_ARM=y
 | 
			
		||||
CONFIG_XZ_DEC_BCJ=y
 | 
			
		||||
CONFIG_ZBOOT_ROM_BSS=0x0
 | 
			
		||||
CONFIG_ZBOOT_ROM_TEXT=0x0
 | 
			
		||||
CONFIG_ZLIB_DEFLATE=y
 | 
			
		||||
CONFIG_ZLIB_INFLATE=y
 | 
			
		||||
CONFIG_ZONE_DMA_FLAG=0
 | 
			
		||||
							
								
								
									
										748
									
								
								target/linux/mvebu/patches-4.4/002-add_powertables.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										748
									
								
								target/linux/mvebu/patches-4.4/002-add_powertables.patch
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,748 @@
 | 
			
		||||
--- a/arch/arm/boot/dts/armada-xp-linksys-mamba.dts
 | 
			
		||||
+++ b/arch/arm/boot/dts/armada-xp-linksys-mamba.dts
 | 
			
		||||
@@ -86,12 +86,100 @@
 | 
			
		||||
 			pcie@2,0 {
 | 
			
		||||
 				/* Port 0, Lane 1 */
 | 
			
		||||
 				status = "okay";
 | 
			
		||||
+
 | 
			
		||||
+				mwlwifi {
 | 
			
		||||
+					marvell,5ghz = <0>;
 | 
			
		||||
+					marvell,chainmask = <4 4>;
 | 
			
		||||
+					marvell,powertable {
 | 
			
		||||
+						FCC =
 | 
			
		||||
+							<1 0 0x17 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0xf 0xf 0xf 0xf 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<2 0 0x17 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x10 0x10 0x10 0x10 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<3 0 0x17 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x10 0x10 0x10 0x10 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<4 0 0x17 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x10 0x10 0x10 0x10 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<5 0 0x17 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x10 0x10 0x10 0x10 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<6 0 0x17 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x10 0x10 0x10 0x10 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<7 0 0x17 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x10 0x10 0x10 0x10 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<8 0 0x17 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x10 0x10 0x10 0x10 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<9 0 0x17 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x10 0x10 0x10 0x10 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<10 0 0x17 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x10 0x10 0x10 0x10 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<11 0 0x17 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x0 0x0 0x0 0x0 0 0xf>;
 | 
			
		||||
+
 | 
			
		||||
+						ETSI =
 | 
			
		||||
+							<1 0 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<2 0 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<3 0 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<4 0 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<5 0 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<6 0 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<7 0 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<8 0 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<9 0 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<10 0 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<11 0 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<12 0 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<13 0 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0x0 0x0 0x0 0x0 0 0xf>;
 | 
			
		||||
+					};
 | 
			
		||||
+				};
 | 
			
		||||
 			};
 | 
			
		||||
 
 | 
			
		||||
 			/* Second mini-PCIe port */
 | 
			
		||||
 			pcie@3,0 {
 | 
			
		||||
 				/* Port 0, Lane 3 */
 | 
			
		||||
 				status = "okay";
 | 
			
		||||
+
 | 
			
		||||
+				mwlwifi {
 | 
			
		||||
+					marvell,2ghz = <0>;
 | 
			
		||||
+					marvell,chainmask = <4 4>;
 | 
			
		||||
+					marvell,powertable {
 | 
			
		||||
+						FCC =
 | 
			
		||||
+							<36 0 0x8 0x8 0x8 0x8 0x8 0x8 0x8 0x8 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0 0xf>,
 | 
			
		||||
+							<40 0 0x8 0x8 0x8 0x8 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0 0xf>,
 | 
			
		||||
+							<44 0 0x8 0x8 0x8 0x8 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0 0xf>,
 | 
			
		||||
+							<48 0 0x8 0x8 0x8 0x8 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0 0xf>,
 | 
			
		||||
+							<52 0 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0 0xf>,
 | 
			
		||||
+							<56 0 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0 0xf>,
 | 
			
		||||
+							<60 0 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0 0xf>,
 | 
			
		||||
+							<64 0 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0 0xf>,
 | 
			
		||||
+							<100 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
 | 
			
		||||
+							<104 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
 | 
			
		||||
+							<108 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
 | 
			
		||||
+							<112 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
 | 
			
		||||
+							<116 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
 | 
			
		||||
+							<120 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
 | 
			
		||||
+							<124 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
 | 
			
		||||
+							<128 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
 | 
			
		||||
+							<132 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
 | 
			
		||||
+							<136 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
 | 
			
		||||
+							<140 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
 | 
			
		||||
+							<149 0 0x16 0x16 0x16 0x16 0x14 0x14 0x14 0x14 0x15 0x15 0x15 0x15 0x14 0x14 0x14 0x14 0 0xf>,
 | 
			
		||||
+							<153 0 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x14 0x14 0x14 0x14 0 0xf>,
 | 
			
		||||
+							<157 0 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x14 0x14 0x14 0x14 0 0xf>,
 | 
			
		||||
+							<161 0 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x14 0x14 0x14 0x14 0 0xf>,
 | 
			
		||||
+							<165 0 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x15 0x15 0x15 0x15 0x14 0x14 0x14 0x14 0 0xf>;
 | 
			
		||||
+
 | 
			
		||||
+						ETSI =
 | 
			
		||||
+							<36 0 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xd 0xd 0xd 0xd 0xc 0xc 0xc 0xc 0 0xf>,
 | 
			
		||||
+							<40 0 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xd 0xd 0xd 0xd 0xc 0xc 0xc 0xc 0 0xf>,
 | 
			
		||||
+							<44 0 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xd 0xd 0xd 0xd 0xc 0xc 0xc 0xc 0 0xf>,
 | 
			
		||||
+							<48 0 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xd 0xd 0xd 0xd 0xc 0xc 0xc 0xc 0 0xf>,
 | 
			
		||||
+							<52 0 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xd 0xd 0xd 0xd 0xc 0xc 0xc 0xc 0 0xf>,
 | 
			
		||||
+							<56 0 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xd 0xd 0xd 0xd 0xc 0xc 0xc 0xc 0 0xf>,
 | 
			
		||||
+							<60 0 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xd 0xd 0xd 0xd 0xc 0xc 0xc 0xc 0 0xf>,
 | 
			
		||||
+							<64 0 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xd 0xd 0xd 0xd 0xc 0xc 0xc 0xc 0 0xf>,
 | 
			
		||||
+							<100 0 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xd 0xd 0xd 0xd 0xc 0xc 0xc 0xc 0 0xf>,
 | 
			
		||||
+							<104 0 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xd 0xd 0xd 0xd 0xc 0xc 0xc 0xc 0 0xf>,
 | 
			
		||||
+							<108 0 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xd 0xd 0xd 0xd 0xc 0xc 0xc 0xc 0 0xf>,
 | 
			
		||||
+							<112 0 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xd 0xd 0xd 0xd 0xc 0xc 0xc 0xc 0 0xf>,
 | 
			
		||||
+							<116 0 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xd 0xd 0xd 0xd 0xc 0xc 0xc 0xc 0 0xf>,
 | 
			
		||||
+							<120 0 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xd 0xd 0xd 0xd 0xc 0xc 0xc 0xc 0 0xf>,
 | 
			
		||||
+							<124 0 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xd 0xd 0xd 0xd 0xc 0xc 0xc 0xc 0 0xf>,
 | 
			
		||||
+							<128 0 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xd 0xd 0xd 0xd 0xc 0xc 0xc 0xc 0 0xf>,
 | 
			
		||||
+							<132 0 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xd 0xd 0xd 0xd 0xc 0xc 0xc 0xc 0 0xf>,
 | 
			
		||||
+							<136 0 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xd 0xd 0xd 0xd 0xc 0xc 0xc 0xc 0 0xf>,
 | 
			
		||||
+							<140 0 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xd 0xd 0xd 0xd 0xc 0xc 0xc 0xc 0 0xf>,
 | 
			
		||||
+							<149 0 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xd 0xd 0xd 0xd 0xc 0xc 0xc 0xc 0 0xf>;
 | 
			
		||||
+					};
 | 
			
		||||
+				};
 | 
			
		||||
 			};
 | 
			
		||||
 		};
 | 
			
		||||
 
 | 
			
		||||
--- a/arch/arm/boot/dts/armada-385-linksys-cobra.dts
 | 
			
		||||
+++ b/arch/arm/boot/dts/armada-385-linksys-cobra.dts
 | 
			
		||||
@@ -100,6 +100,212 @@
 | 
			
		||||
 				};
 | 
			
		||||
 			};
 | 
			
		||||
 		};
 | 
			
		||||
+
 | 
			
		||||
+		pcie-controller {
 | 
			
		||||
+			pcie@1,0 {
 | 
			
		||||
+				mwlwifi {
 | 
			
		||||
+					marvell,2ghz = <0>;
 | 
			
		||||
+					marvell,chainmask = <4 4>;
 | 
			
		||||
+					marvell,powertable {
 | 
			
		||||
+						AU =
 | 
			
		||||
+							<36 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<40 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<44 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<48 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<52 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<56 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<60 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<64 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<100 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
 | 
			
		||||
+							<104 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
 | 
			
		||||
+							<108 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
 | 
			
		||||
+							<112 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
 | 
			
		||||
+							<116 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
 | 
			
		||||
+							<120 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
 | 
			
		||||
+							<124 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
 | 
			
		||||
+							<128 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
 | 
			
		||||
+							<132 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
 | 
			
		||||
+							<136 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
 | 
			
		||||
+							<140 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
 | 
			
		||||
+							<149 0 0x19 0x19 0x19 0x17 0x19 0x19 0x16 0x15 0x19 0x19 0x16 0x15 0x19 0x19 0x16 0x15 0 0xf>,
 | 
			
		||||
+							<153 0 0x19 0x19 0x19 0x17 0x19 0x19 0x16 0x15 0x19 0x19 0x16 0x15 0x19 0x19 0x16 0x15 0 0xf>,
 | 
			
		||||
+							<157 0 0x19 0x19 0x19 0x17 0x19 0x19 0x16 0x15 0x19 0x19 0x16 0x15 0x19 0x19 0x16 0x15 0 0xf>,
 | 
			
		||||
+							<161 0 0x19 0x19 0x19 0x17 0x19 0x19 0x16 0x15 0x19 0x19 0x16 0x15 0x19 0x19 0x16 0x15 0 0xf>,
 | 
			
		||||
+							<165 0 0x19 0x19 0x19 0x17 0x19 0x19 0x16 0x15 0x19 0x19 0x16 0x15 0x19 0x19 0x16 0x15 0 0xf>;
 | 
			
		||||
+						CA =
 | 
			
		||||
+							<36 0 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0 0xf>,
 | 
			
		||||
+							<40 0 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0 0xf>,
 | 
			
		||||
+							<44 0 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0 0xf>,
 | 
			
		||||
+							<48 0 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0 0xf>,
 | 
			
		||||
+							<52 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<56 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<60 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<64 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<100 0 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<104 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<108 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<112 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<116 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<120 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<124 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<128 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<132 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<136 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<140 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<149 0 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0 0xf>,
 | 
			
		||||
+							<153 0 0x16 0x16 0x16 0x16 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0 0xf>,
 | 
			
		||||
+							<157 0 0x16 0x16 0x16 0x16 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0 0xf>,
 | 
			
		||||
+							<161 0 0x16 0x16 0x16 0x16 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0 0xf>,
 | 
			
		||||
+							<165 0 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0 0xf>;
 | 
			
		||||
+						CN =
 | 
			
		||||
+							<36 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<40 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<44 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<48 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<52 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<56 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<60 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<64 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<100 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<104 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<108 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<112 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<116 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<120 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<124 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<128 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<132 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<136 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<140 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<149 0 0x14 0x14 0x14 0x14 0x13 0x13 0x13 0x13 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<153 0 0x16 0x16 0x16 0x16 0x15 0x15 0x15 0x15 0x14 0x14 0x14 0x14 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<157 0 0x16 0x16 0x16 0x16 0x15 0x15 0x15 0x15 0x14 0x14 0x14 0x14 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<161 0 0x16 0x16 0x16 0x16 0x15 0x15 0x15 0x15 0x14 0x14 0x14 0x14 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<165 0 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x14 0x14 0x14 0x14 0x10 0x10 0x10 0x10 0 0xf>;
 | 
			
		||||
+						ETSI =
 | 
			
		||||
+							<36 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<40 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<44 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<48 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<52 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<56 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<60 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<64 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<100 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<104 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<108 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<112 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<116 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<120 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<124 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<128 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<132 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<136 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<140 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<149 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>;
 | 
			
		||||
+						FCC =
 | 
			
		||||
+							<36 0 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0xf 0xf 0xf 0xf 0 0xf>,
 | 
			
		||||
+							<40 0 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0xf 0xf 0xf 0xf 0 0xf>,
 | 
			
		||||
+							<44 0 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0xf 0xf 0xf 0xf 0 0xf>,
 | 
			
		||||
+							<48 0 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0xf 0xf 0xf 0xf 0 0xf>,
 | 
			
		||||
+							<52 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<56 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<60 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<64 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<100 0 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<104 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<108 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<112 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<116 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<120 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<124 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<128 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<132 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<136 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<140 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<149 0 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0 0xf>,
 | 
			
		||||
+							<153 0 0x16 0x16 0x16 0x16 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0 0xf>,
 | 
			
		||||
+							<157 0 0x16 0x16 0x16 0x16 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0 0xf>,
 | 
			
		||||
+							<161 0 0x16 0x16 0x16 0x16 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0 0xf>,
 | 
			
		||||
+							<165 0 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0 0xf>;
 | 
			
		||||
+					};
 | 
			
		||||
+				};
 | 
			
		||||
+			};
 | 
			
		||||
+
 | 
			
		||||
+			pcie@2,0 {
 | 
			
		||||
+				mwlwifi {
 | 
			
		||||
+					marvell,5ghz = <0>;
 | 
			
		||||
+					marvell,chainmask = <4 4>;
 | 
			
		||||
+					marvell,powertable {
 | 
			
		||||
+						AU =
 | 
			
		||||
+							<1 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<2 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<3 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<4 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<5 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<6 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<7 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<8 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<9 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<10 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<11 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>;
 | 
			
		||||
+						CA =
 | 
			
		||||
+							<1 0 0x17 0x10 0x10 0x10 0xf 0xf 0xf 0xf 0xe 0xe 0xe 0xe 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<2 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<3 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<4 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<5 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<6 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<7 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<8 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<9 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<10 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<11 0 0x17 0x12 0x12 0x12 0x13 0x13 0x13 0x13 0xf 0xf 0xf 0xf 0x0 0x0 0x0 0x0 0 0xf>;
 | 
			
		||||
+						CN =
 | 
			
		||||
+							<1 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<2 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<3 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<4 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<5 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<6 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<7 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<8 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<9 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<10 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<11 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<12 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<13 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<14 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>;
 | 
			
		||||
+						ETSI =
 | 
			
		||||
+							<1 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<2 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<3 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<4 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<5 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<6 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<7 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<8 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<9 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<10 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<11 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<12 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<13 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>;
 | 
			
		||||
+						FCC =
 | 
			
		||||
+							<1 0 0x17 0x10 0x10 0x10 0xf 0xf 0xf 0xf 0xe 0xe 0xe 0xe 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<2 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<3 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<4 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<5 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<6 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<7 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<8 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<9 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<10 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<11 0 0x17 0x12 0x12 0x12 0x13 0x13 0x13 0x13 0xf 0xf 0xf 0xf 0x0 0x0 0x0 0x0 0 0xf>;
 | 
			
		||||
+					};
 | 
			
		||||
+				};
 | 
			
		||||
+			};
 | 
			
		||||
+		};
 | 
			
		||||
 	};
 | 
			
		||||
 
 | 
			
		||||
 	gpio-leds {
 | 
			
		||||
--- a/arch/arm/boot/dts/armada-385-linksys-caiman.dts
 | 
			
		||||
+++ b/arch/arm/boot/dts/armada-385-linksys-caiman.dts
 | 
			
		||||
@@ -100,6 +100,212 @@
 | 
			
		||||
 				};
 | 
			
		||||
 			};
 | 
			
		||||
 		};
 | 
			
		||||
+
 | 
			
		||||
+		pcie-controller {
 | 
			
		||||
+			pcie@1,0 {
 | 
			
		||||
+				mwlwifi {
 | 
			
		||||
+					marvell,2ghz = <0>;
 | 
			
		||||
+					marvell,chainmask = <2 2>;
 | 
			
		||||
+					marvell,powertable {
 | 
			
		||||
+						AU =
 | 
			
		||||
+							<36 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
 | 
			
		||||
+							<40 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
 | 
			
		||||
+							<44 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
 | 
			
		||||
+							<48 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
 | 
			
		||||
+							<52 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
 | 
			
		||||
+							<56 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
 | 
			
		||||
+							<60 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
 | 
			
		||||
+							<64 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
 | 
			
		||||
+							<100 0 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x15 0x17 0x17 0x17 0x14 0x17 0x17 0x17 0x14 0 0xf>,
 | 
			
		||||
+							<104 0 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x15 0x17 0x17 0x17 0x14 0x17 0x17 0x17 0x14 0 0xf>,
 | 
			
		||||
+							<108 0 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x15 0x17 0x17 0x17 0x14 0x17 0x17 0x17 0x14 0 0xf>,
 | 
			
		||||
+							<112 0 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x15 0x17 0x17 0x17 0x14 0x17 0x17 0x17 0x14 0 0xf>,
 | 
			
		||||
+							<116 0 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x15 0x17 0x17 0x17 0x14 0x17 0x17 0x17 0x14 0 0xf>,
 | 
			
		||||
+							<120 0 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x15 0x17 0x17 0x17 0x14 0x17 0x17 0x17 0x14 0 0xf>,
 | 
			
		||||
+							<124 0 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x15 0x17 0x17 0x17 0x14 0x17 0x17 0x17 0x14 0 0xf>,
 | 
			
		||||
+							<128 0 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x15 0x17 0x17 0x17 0x14 0x17 0x17 0x17 0x14 0 0xf>,
 | 
			
		||||
+							<132 0 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x15 0x17 0x17 0x17 0x14 0x17 0x17 0x17 0x14 0 0xf>,
 | 
			
		||||
+							<136 0 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x15 0x17 0x17 0x17 0x14 0x17 0x17 0x17 0x14 0 0xf>,
 | 
			
		||||
+							<140 0 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x15 0x17 0x17 0x17 0x14 0x17 0x17 0x17 0x14 0 0xf>,
 | 
			
		||||
+							<149 0 0x1a 0x1a 0x18 0x17 0x1a 0x1a 0x17 0x15 0x1a 0x1a 0x17 0x14 0x1a 0x1a 0x17 0x14 0 0xf>,
 | 
			
		||||
+							<153 0 0x1a 0x1a 0x18 0x17 0x1a 0x1a 0x17 0x15 0x1a 0x1a 0x17 0x14 0x1a 0x1a 0x17 0x14 0 0xf>,
 | 
			
		||||
+							<157 0 0x1a 0x1a 0x18 0x17 0x1a 0x1a 0x17 0x15 0x1a 0x1a 0x17 0x14 0x1a 0x1a 0x17 0x14 0 0xf>,
 | 
			
		||||
+							<161 0 0x1a 0x1a 0x18 0x17 0x1a 0x1a 0x17 0x15 0x1a 0x1a 0x17 0x14 0x1a 0x1a 0x17 0x14 0 0xf>,
 | 
			
		||||
+							<165 0 0x1a 0x1a 0x18 0x17 0x1a 0x1a 0x17 0x15 0x1a 0x1a 0x17 0x14 0x1a 0x1a 0x17 0x14 0 0xf>;
 | 
			
		||||
+						CA =
 | 
			
		||||
+							<36 0 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0 0xf>,
 | 
			
		||||
+							<40 0 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0 0xf>,
 | 
			
		||||
+							<44 0 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0 0xf>,
 | 
			
		||||
+							<48 0 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0 0xf>,
 | 
			
		||||
+							<52 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<56 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<60 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<64 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<100 0 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<104 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<108 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<112 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<116 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<120 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<124 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<128 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<132 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<136 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<140 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<149 0 0x1a 0x1a 0x18 0x17 0x19 0x19 0x17 0x15 0x18 0x18 0x17 0x14 0x15 0x15 0x15 0x14 0 0xf>,
 | 
			
		||||
+							<153 0 0x1a 0x1a 0x18 0x17 0x1a 0x1a 0x17 0x15 0x1a 0x1a 0x17 0x14 0x15 0x15 0x15 0x14 0 0xf>,
 | 
			
		||||
+							<157 0 0x1a 0x1a 0x18 0x17 0x1a 0x1a 0x17 0x15 0x1a 0x1a 0x17 0x14 0x15 0x15 0x15 0x14 0 0xf>,
 | 
			
		||||
+							<161 0 0x1a 0x1a 0x18 0x17 0x1a 0x1a 0x17 0x15 0x1a 0x1a 0x17 0x14 0x15 0x15 0x15 0x14 0 0xf>,
 | 
			
		||||
+							<165 0 0x1a 0x1a 0x18 0x17 0x1a 0x1a 0x17 0x15 0x1a 0x1a 0x17 0x14 0x15 0x15 0x15 0x14 0 0xf>;
 | 
			
		||||
+						CN =
 | 
			
		||||
+							<36 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
 | 
			
		||||
+							<40 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
 | 
			
		||||
+							<44 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
 | 
			
		||||
+							<48 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
 | 
			
		||||
+							<52 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
 | 
			
		||||
+							<56 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
 | 
			
		||||
+							<60 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
 | 
			
		||||
+							<64 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
 | 
			
		||||
+							<100 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
 | 
			
		||||
+							<104 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
 | 
			
		||||
+							<108 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
 | 
			
		||||
+							<112 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
 | 
			
		||||
+							<116 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
 | 
			
		||||
+							<120 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
 | 
			
		||||
+							<124 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
 | 
			
		||||
+							<128 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
 | 
			
		||||
+							<132 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
 | 
			
		||||
+							<136 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
 | 
			
		||||
+							<140 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
 | 
			
		||||
+							<149 0 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x14 0x14 0x14 0x14 0x11 0x11 0x11 0x11 0 0xf>,
 | 
			
		||||
+							<153 0 0x1a 0x1a 0x18 0x17 0x1a 0x1a 0x17 0x15 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0 0xf>,
 | 
			
		||||
+							<157 0 0x1a 0x1a 0x18 0x17 0x1a 0x1a 0x17 0x15 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0 0xf>,
 | 
			
		||||
+							<161 0 0x1a 0x1a 0x18 0x17 0x1a 0x1a 0x17 0x15 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0 0xf>,
 | 
			
		||||
+							<165 0 0x15 0x15 0x15 0x15 0x16 0x16 0x16 0x15 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0 0xf>;
 | 
			
		||||
+						ETSI =
 | 
			
		||||
+							<36 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
 | 
			
		||||
+							<40 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
 | 
			
		||||
+							<44 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
 | 
			
		||||
+							<48 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
 | 
			
		||||
+							<52 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
 | 
			
		||||
+							<56 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
 | 
			
		||||
+							<60 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
 | 
			
		||||
+							<64 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
 | 
			
		||||
+							<100 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
 | 
			
		||||
+							<104 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
 | 
			
		||||
+							<108 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
 | 
			
		||||
+							<112 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
 | 
			
		||||
+							<116 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
 | 
			
		||||
+							<120 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
 | 
			
		||||
+							<124 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
 | 
			
		||||
+							<128 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
 | 
			
		||||
+							<132 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
 | 
			
		||||
+							<136 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
 | 
			
		||||
+							<140 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
 | 
			
		||||
+							<149 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>;
 | 
			
		||||
+						FCC =
 | 
			
		||||
+							<36 0 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<40 0 0x19 0x19 0x18 0x17 0x19 0x19 0x17 0x15 0x17 0x17 0x17 0x14 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<44 0 0x19 0x19 0x18 0x17 0x19 0x19 0x17 0x15 0x17 0x17 0x17 0x14 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<48 0 0x1a 0x1a 0x18 0x17 0x1a 0x1a 0x17 0x15 0x17 0x17 0x17 0x14 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<52 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<56 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<60 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<64 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<100 0 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<104 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<108 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<112 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<116 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<120 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<124 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<128 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<132 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<136 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<140 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<149 0 0x1a 0x1a 0x18 0x17 0x19 0x19 0x17 0x15 0x18 0x18 0x17 0x14 0x15 0x15 0x15 0x14 0 0xf>,
 | 
			
		||||
+							<153 0 0x1a 0x1a 0x18 0x17 0x1a 0x1a 0x17 0x15 0x1a 0x1a 0x17 0x14 0x15 0x15 0x15 0x14 0 0xf>,
 | 
			
		||||
+							<157 0 0x1a 0x1a 0x18 0x17 0x1a 0x1a 0x17 0x15 0x1a 0x1a 0x17 0x14 0x15 0x15 0x15 0x14 0 0xf>,
 | 
			
		||||
+							<161 0 0x1a 0x1a 0x18 0x17 0x1a 0x1a 0x17 0x15 0x1a 0x1a 0x17 0x14 0x15 0x15 0x15 0x14 0 0xf>,
 | 
			
		||||
+							<165 0 0x1a 0x1a 0x18 0x17 0x1a 0x1a 0x17 0x15 0x1a 0x1a 0x17 0x14 0x15 0x15 0x15 0x14 0 0xf>;
 | 
			
		||||
+					};
 | 
			
		||||
+				};
 | 
			
		||||
+			};
 | 
			
		||||
+
 | 
			
		||||
+			pcie@2,0 {
 | 
			
		||||
+				mwlwifi {
 | 
			
		||||
+					marvell,5ghz = <0>;
 | 
			
		||||
+					marvell,chainmask = <2 2>;
 | 
			
		||||
+					marvell,powertable {
 | 
			
		||||
+						AU =
 | 
			
		||||
+							<1 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<2 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<3 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<4 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<5 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<6 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<7 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<8 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<9 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<10 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<11 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>;
 | 
			
		||||
+						CA =
 | 
			
		||||
+							<1 0 0x19 0x14 0x14 0x14 0x13 0x13 0x13 0x13 0x10 0x10 0x10 0x10 0x00 0x00 0x00 0x00 0 0xf>,
 | 
			
		||||
+							<2 0 0x1a 0x19 0x18 0x17 0x19 0x19 0x17 0x16 0x14 0x14 0x14 0x14 0x00 0x00 0x00 0x00 0 0xf>,
 | 
			
		||||
+							<3 0 0x1a 0x19 0x18 0x17 0x19 0x19 0x17 0x16 0x14 0x14 0x14 0x14 0x00 0x00 0x00 0x00 0 0xf>,
 | 
			
		||||
+							<4 0 0x1a 0x19 0x18 0x17 0x19 0x19 0x17 0x16 0x14 0x14 0x14 0x14 0x00 0x00 0x00 0x00 0 0xf>,
 | 
			
		||||
+							<5 0 0x1a 0x19 0x18 0x17 0x19 0x19 0x17 0x16 0x14 0x14 0x14 0x14 0x00 0x00 0x00 0x00 0 0xf>,
 | 
			
		||||
+							<6 0 0x1a 0x19 0x18 0x17 0x19 0x19 0x17 0x16 0x14 0x14 0x14 0x14 0x00 0x00 0x00 0x00 0 0xf>,
 | 
			
		||||
+							<7 0 0x1a 0x19 0x18 0x17 0x19 0x19 0x17 0x16 0x14 0x14 0x14 0x14 0x00 0x00 0x00 0x00 0 0xf>,
 | 
			
		||||
+							<8 0 0x1a 0x19 0x18 0x17 0x19 0x19 0x17 0x16 0x14 0x14 0x14 0x14 0x00 0x00 0x00 0x00 0 0xf>,
 | 
			
		||||
+							<9 0 0x1a 0x19 0x18 0x17 0x19 0x19 0x17 0x16 0x14 0x14 0x14 0x14 0x00 0x00 0x00 0x00 0 0xf>,
 | 
			
		||||
+							<10 0 0x1a 0x19 0x18 0x17 0x19 0x19 0x17 0x16 0x14 0x14 0x14 0x14 0x00 0x00 0x00 0x00 0 0xf>,
 | 
			
		||||
+							<11 0 0x19 0x15 0x15 0x15 0x14 0x14 0x14 0x14 0x13 0x13 0x13 0x13 0x00 0x00 0x00 0x00 0 0xf>;
 | 
			
		||||
+						CN =
 | 
			
		||||
+							<1 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<2 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<3 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<4 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<5 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<6 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<7 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<8 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<9 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<10 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<11 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<12 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<13 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<14 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>;
 | 
			
		||||
+						ETSI =
 | 
			
		||||
+							<1 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<2 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<3 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<4 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<5 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<6 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<7 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<8 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<9 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<10 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<11 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<12 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<13 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>;
 | 
			
		||||
+						FCC =
 | 
			
		||||
+							<1 0 0x19 0x14 0x14 0x14 0x13 0x13 0x13 0x13 0x10 0x10 0x10 0x10 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<2 0 0x1a 0x19 0x18 0x17 0x19 0x19 0x17 0x16 0x14 0x14 0x14 0x14 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<3 0 0x1a 0x19 0x18 0x17 0x19 0x19 0x17 0x16 0x14 0x14 0x14 0x14 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<4 0 0x1a 0x19 0x18 0x17 0x19 0x19 0x17 0x16 0x14 0x14 0x14 0x14 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<5 0 0x1a 0x19 0x18 0x17 0x19 0x19 0x17 0x16 0x14 0x14 0x14 0x14 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<6 0 0x1a 0x19 0x18 0x17 0x19 0x19 0x17 0x16 0x14 0x14 0x14 0x14 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<7 0 0x1a 0x19 0x18 0x17 0x19 0x19 0x17 0x16 0x14 0x14 0x14 0x14 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<8 0 0x1a 0x19 0x18 0x17 0x19 0x19 0x17 0x16 0x14 0x14 0x14 0x14 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<9 0 0x1a 0x19 0x18 0x17 0x19 0x19 0x17 0x16 0x14 0x14 0x14 0x14 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<10 0 0x1a 0x19 0x18 0x17 0x19 0x19 0x17 0x16 0x14 0x14 0x14 0x14 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<11 0 0x19 0x15 0x15 0x15 0x14 0x14 0x14 0x14 0x13 0x13 0x13 0x13 0x0 0x0 0x0 0x0 0 0xf>;
 | 
			
		||||
+					};
 | 
			
		||||
+				};
 | 
			
		||||
+			};
 | 
			
		||||
+		};
 | 
			
		||||
 	};
 | 
			
		||||
 
 | 
			
		||||
 	gpio-leds {
 | 
			
		||||
--- a/arch/arm/boot/dts/armada-385-linksys-shelby.dts
 | 
			
		||||
+++ b/arch/arm/boot/dts/armada-385-linksys-shelby.dts
 | 
			
		||||
@@ -100,6 +100,212 @@
 | 
			
		||||
 				};
 | 
			
		||||
 			};
 | 
			
		||||
 		};
 | 
			
		||||
+
 | 
			
		||||
+		pcie-controller {
 | 
			
		||||
+			pcie@1,0 {
 | 
			
		||||
+				mwlwifi {
 | 
			
		||||
+					marvell,2ghz = <0>;
 | 
			
		||||
+					marvell,chainmask = <4 4>;
 | 
			
		||||
+					marvell,powertable {
 | 
			
		||||
+						AU =
 | 
			
		||||
+							<36 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<40 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<44 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<48 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<52 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<56 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<60 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<64 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<100 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
 | 
			
		||||
+							<104 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
 | 
			
		||||
+							<108 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
 | 
			
		||||
+							<112 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
 | 
			
		||||
+							<116 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
 | 
			
		||||
+							<120 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
 | 
			
		||||
+							<124 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
 | 
			
		||||
+							<128 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
 | 
			
		||||
+							<132 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
 | 
			
		||||
+							<136 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
 | 
			
		||||
+							<140 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
 | 
			
		||||
+							<149 0 0x19 0x19 0x19 0x17 0x19 0x19 0x16 0x15 0x19 0x19 0x16 0x15 0x19 0x19 0x16 0x15 0 0xf>,
 | 
			
		||||
+							<153 0 0x19 0x19 0x19 0x17 0x19 0x19 0x16 0x15 0x19 0x19 0x16 0x15 0x19 0x19 0x16 0x15 0 0xf>,
 | 
			
		||||
+							<157 0 0x19 0x19 0x19 0x17 0x19 0x19 0x16 0x15 0x19 0x19 0x16 0x15 0x19 0x19 0x16 0x15 0 0xf>,
 | 
			
		||||
+							<161 0 0x19 0x19 0x19 0x17 0x19 0x19 0x16 0x15 0x19 0x19 0x16 0x15 0x19 0x19 0x16 0x15 0 0xf>,
 | 
			
		||||
+							<165 0 0x19 0x19 0x19 0x17 0x19 0x19 0x16 0x15 0x19 0x19 0x16 0x15 0x19 0x19 0x16 0x15 0 0xf>;
 | 
			
		||||
+						CA =
 | 
			
		||||
+							<36 0 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0 0xf>,
 | 
			
		||||
+							<40 0 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0 0xf>,
 | 
			
		||||
+							<44 0 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0 0xf>,
 | 
			
		||||
+							<48 0 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0 0xf>,
 | 
			
		||||
+							<52 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<56 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<60 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<64 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<100 0 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<104 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<108 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<112 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<116 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<120 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<124 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<128 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<132 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<136 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<140 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<149 0 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0 0xf>,
 | 
			
		||||
+							<153 0 0x16 0x16 0x16 0x16 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0 0xf>,
 | 
			
		||||
+							<157 0 0x16 0x16 0x16 0x16 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0 0xf>,
 | 
			
		||||
+							<161 0 0x16 0x16 0x16 0x16 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0 0xf>,
 | 
			
		||||
+							<165 0 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0 0xf>;
 | 
			
		||||
+						CN =
 | 
			
		||||
+							<36 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<40 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<44 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<48 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<52 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<56 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<60 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<64 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<100 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<104 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<108 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<112 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<116 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<120 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<124 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<128 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<132 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<136 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<140 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<149 0 0x14 0x14 0x14 0x14 0x13 0x13 0x13 0x13 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<153 0 0x16 0x16 0x16 0x16 0x15 0x15 0x15 0x15 0x14 0x14 0x14 0x14 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<157 0 0x16 0x16 0x16 0x16 0x15 0x15 0x15 0x15 0x14 0x14 0x14 0x14 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<161 0 0x16 0x16 0x16 0x16 0x15 0x15 0x15 0x15 0x14 0x14 0x14 0x14 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<165 0 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x14 0x14 0x14 0x14 0x10 0x10 0x10 0x10 0 0xf>;
 | 
			
		||||
+						ETSI =
 | 
			
		||||
+							<36 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<40 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<44 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<48 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<52 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<56 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<60 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<64 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<100 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<104 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<108 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<112 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<116 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<120 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<124 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<128 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<132 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<136 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<140 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
 | 
			
		||||
+							<149 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>;
 | 
			
		||||
+						FCC =
 | 
			
		||||
+							<36 0 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0xf 0xf 0xf 0xf 0 0xf>,
 | 
			
		||||
+							<40 0 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0xf 0xf 0xf 0xf 0 0xf>,
 | 
			
		||||
+							<44 0 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0xf 0xf 0xf 0xf 0 0xf>,
 | 
			
		||||
+							<48 0 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0xf 0xf 0xf 0xf 0 0xf>,
 | 
			
		||||
+							<52 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<56 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<60 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<64 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<100 0 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<104 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<108 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<112 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<116 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<120 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<124 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<128 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<132 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<136 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<140 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
 | 
			
		||||
+							<149 0 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0 0xf>,
 | 
			
		||||
+							<153 0 0x16 0x16 0x16 0x16 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0 0xf>,
 | 
			
		||||
+							<157 0 0x16 0x16 0x16 0x16 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0 0xf>,
 | 
			
		||||
+							<161 0 0x16 0x16 0x16 0x16 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0 0xf>,
 | 
			
		||||
+							<165 0 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0 0xf>;
 | 
			
		||||
+					};
 | 
			
		||||
+				};
 | 
			
		||||
+			};
 | 
			
		||||
+
 | 
			
		||||
+			pcie@2,0 {
 | 
			
		||||
+				mwlwifi {
 | 
			
		||||
+					marvell,5ghz = <0>;
 | 
			
		||||
+					marvell,chainmask = <4 4>;
 | 
			
		||||
+					marvell,powertable {
 | 
			
		||||
+						AU =
 | 
			
		||||
+							<1 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<2 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<3 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<4 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<5 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<6 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<7 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<8 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<9 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<10 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<11 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>;
 | 
			
		||||
+						CA =
 | 
			
		||||
+							<1 0 0x17 0x10 0x10 0x10 0xf 0xf 0xf 0xf 0xe 0xe 0xe 0xe 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<2 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<3 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<4 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<5 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<6 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<7 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<8 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<9 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<10 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<11 0 0x17 0x12 0x12 0x12 0x13 0x13 0x13 0x13 0xf 0xf 0xf 0xf 0x0 0x0 0x0 0x0 0 0xf>;
 | 
			
		||||
+						CN =
 | 
			
		||||
+							<1 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<2 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<3 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<4 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<5 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<6 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<7 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<8 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<9 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<10 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<11 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<12 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<13 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<14 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>;
 | 
			
		||||
+						ETSI =
 | 
			
		||||
+							<1 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<2 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<3 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<4 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<5 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<6 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<7 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<8 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<9 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<10 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<11 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<12 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<13 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>;
 | 
			
		||||
+						FCC =
 | 
			
		||||
+							<1 0 0x17 0x10 0x10 0x10 0xf 0xf 0xf 0xf 0xe 0xe 0xe 0xe 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<2 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<3 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<4 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<5 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<6 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<7 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<8 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<9 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<10 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
 | 
			
		||||
+							<11 0 0x17 0x12 0x12 0x12 0x13 0x13 0x13 0x13 0xf 0xf 0xf 0xf 0x0 0x0 0x0 0x0 0 0xf>;
 | 
			
		||||
+					};
 | 
			
		||||
+				};
 | 
			
		||||
+			};
 | 
			
		||||
+		};
 | 
			
		||||
 	};
 | 
			
		||||
 
 | 
			
		||||
 	gpio-leds {
 | 
			
		||||
							
								
								
									
										40
									
								
								target/linux/mvebu/patches-4.4/003-add_switch_nodes.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								target/linux/mvebu/patches-4.4/003-add_switch_nodes.patch
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
			
		||||
--- a/arch/arm/boot/dts/armada-xp-linksys-mamba.dts
 | 
			
		||||
+++ b/arch/arm/boot/dts/armada-xp-linksys-mamba.dts
 | 
			
		||||
@@ -467,6 +467,16 @@
 | 
			
		||||
 			};
 | 
			
		||||
 		};
 | 
			
		||||
 	};
 | 
			
		||||
+
 | 
			
		||||
+	mvsw61xx {
 | 
			
		||||
+		compatible = "marvell,88e6172";
 | 
			
		||||
+		status = "okay";
 | 
			
		||||
+		reg = <0x10>;
 | 
			
		||||
+
 | 
			
		||||
+		mii-bus = <&mdio>;
 | 
			
		||||
+		cpu-port-0 = <5>;
 | 
			
		||||
+		cpu-port-1 = <6>;
 | 
			
		||||
+	};
 | 
			
		||||
 };
 | 
			
		||||
 
 | 
			
		||||
 &pinctrl {
 | 
			
		||||
--- a/arch/arm/boot/dts/armada-385-linksys.dtsi
 | 
			
		||||
+++ b/arch/arm/boot/dts/armada-385-linksys.dtsi
 | 
			
		||||
@@ -309,6 +309,18 @@
 | 
			
		||||
 			};
 | 
			
		||||
 		};
 | 
			
		||||
 	};
 | 
			
		||||
+
 | 
			
		||||
+	mvsw61xx {
 | 
			
		||||
+		#address-cells = <1>;
 | 
			
		||||
+		#size-cells = <0>;
 | 
			
		||||
+		compatible = "marvell,88e6176";
 | 
			
		||||
+		status = "okay";
 | 
			
		||||
+		reg = <0x10>;
 | 
			
		||||
+
 | 
			
		||||
+		mii-bus = <&mdio>;
 | 
			
		||||
+		cpu-port-0 = <5>;
 | 
			
		||||
+		cpu-port-1 = <6>;
 | 
			
		||||
+	};
 | 
			
		||||
 };
 | 
			
		||||
 
 | 
			
		||||
 &pinctrl {
 | 
			
		||||
							
								
								
									
										11
									
								
								target/linux/mvebu/patches-4.4/010-build_new_dtbs.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								target/linux/mvebu/patches-4.4/010-build_new_dtbs.patch
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
--- a/arch/arm/boot/dts/Makefile
 | 
			
		||||
+++ b/arch/arm/boot/dts/Makefile
 | 
			
		||||
@@ -748,6 +748,8 @@ dtb-$(CONFIG_MACH_ARMADA_38X) += \
 | 
			
		||||
 	armada-385-db-ap.dtb \
 | 
			
		||||
 	armada-385-linksys-caiman.dtb \
 | 
			
		||||
 	armada-385-linksys-cobra.dtb \
 | 
			
		||||
+	armada-385-linksys-rango.dtb \
 | 
			
		||||
+	armada-385-linksys-shelby.dtb \
 | 
			
		||||
 	armada-388-db.dtb \
 | 
			
		||||
 	armada-388-gp.dtb \
 | 
			
		||||
 	armada-388-rd.dtb
 | 
			
		||||
@@ -0,0 +1,428 @@
 | 
			
		||||
From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
 | 
			
		||||
Date: Wed, 10 Feb 2016 14:54:21 +0100
 | 
			
		||||
Subject: [PATCH] mtd: nand: pxa3xx_nand: add support for partial chunks
 | 
			
		||||
 | 
			
		||||
This commit is needed to properly support the 8-bits ECC configuration
 | 
			
		||||
with 4KB pages.
 | 
			
		||||
 | 
			
		||||
When pages larger than 2 KB are used on platforms using the PXA3xx
 | 
			
		||||
NAND controller, the reading/programming operations need to be split
 | 
			
		||||
in chunks of 2 KBs or less because the controller FIFO is limited to
 | 
			
		||||
about 2 KB (i.e a bit more than 2 KB to accommodate OOB data). Due to
 | 
			
		||||
this requirement, the data layout on NAND is a bit strange, with ECC
 | 
			
		||||
interleaved with data, at the end of each chunk.
 | 
			
		||||
 | 
			
		||||
When a 4-bits ECC configuration is used with 4 KB pages, the physical
 | 
			
		||||
data layout on the NAND looks like this:
 | 
			
		||||
 | 
			
		||||
| 2048 data | 32 spare | 30 ECC | 2048 data | 32 spare | 30 ECC |
 | 
			
		||||
 | 
			
		||||
So the data chunks have an equal size, 2080 bytes for each chunk,
 | 
			
		||||
which the driver supports properly.
 | 
			
		||||
 | 
			
		||||
When a 8-bits ECC configuration is used with 4KB pages, the physical
 | 
			
		||||
data layout on the NAND looks like this:
 | 
			
		||||
 | 
			
		||||
| 1024 data | 30 ECC | 1024 data | 30 ECC | 1024 data | 30 ECC | 1024 data | 30 ECC | 64 spare | 30 ECC |
 | 
			
		||||
 | 
			
		||||
So, the spare area is stored in its own chunk, which has a different
 | 
			
		||||
size than the other chunks. Since OOB is not used by UBIFS, the initial
 | 
			
		||||
implementation of the driver has chosen to not support reading this
 | 
			
		||||
additional "spare" chunk of data.
 | 
			
		||||
 | 
			
		||||
Unfortunately, Marvell has chosen to store the BBT signature in the
 | 
			
		||||
OOB area. Therefore, if the driver doesn't read this spare area, Linux
 | 
			
		||||
has no way of finding the BBT. It thinks there is no BBT, and rewrites
 | 
			
		||||
one, which U-Boot does not recognize, causing compatibility problems
 | 
			
		||||
between the bootloader and the kernel in terms of NAND usage.
 | 
			
		||||
 | 
			
		||||
To fix this, this commit implements the support for reading a partial
 | 
			
		||||
last chunk. This support is currently only useful for the case of 8
 | 
			
		||||
bits ECC with 4 KB pages, but it will be useful in the future to
 | 
			
		||||
enable other configurations such as 12 bits and 16 bits ECC with 4 KB
 | 
			
		||||
pages, or 8 bits ECC with 8 KB pages, etc. All those configurations
 | 
			
		||||
have a "last" chunk that doesn't have the same size as the other
 | 
			
		||||
chunks.
 | 
			
		||||
 | 
			
		||||
In order to implement reading of the last chunk, this commit:
 | 
			
		||||
 | 
			
		||||
 - Adds a number of new fields to the pxa3xx_nand_info to describe how
 | 
			
		||||
   many full chunks and how many chunks we have, the size of full
 | 
			
		||||
   chunks and partial chunks, both in terms of data area and spare
 | 
			
		||||
   area.
 | 
			
		||||
 | 
			
		||||
 - Fills in the step_chunk_size and step_spare_size variables to
 | 
			
		||||
   describe how much data and spare should be read/written for the
 | 
			
		||||
   current read/program step.
 | 
			
		||||
 | 
			
		||||
 - Reworks the state machine to accommodate doing the additional read
 | 
			
		||||
   or program step when a last partial chunk is used.
 | 
			
		||||
 | 
			
		||||
This commit has been tested on a Marvell Armada 398 DB board, with a
 | 
			
		||||
4KB page NAND, tested in both 4 bits ECC and 8 bits ECC
 | 
			
		||||
configurations. Robert Jarzmik has tested on some PXA platforms.
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
 | 
			
		||||
Tested-by: Robert Jarzmik <robert.jarzmik@free.fr>
 | 
			
		||||
Acked-by: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
 | 
			
		||||
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
--- a/drivers/mtd/nand/pxa3xx_nand.c
 | 
			
		||||
+++ b/drivers/mtd/nand/pxa3xx_nand.c
 | 
			
		||||
@@ -228,15 +228,44 @@ struct pxa3xx_nand_info {
 | 
			
		||||
 	int			use_spare;	/* use spare ? */
 | 
			
		||||
 	int			need_wait;
 | 
			
		||||
 
 | 
			
		||||
-	unsigned int		data_size;	/* data to be read from FIFO */
 | 
			
		||||
-	unsigned int		chunk_size;	/* split commands chunk size */
 | 
			
		||||
-	unsigned int		oob_size;
 | 
			
		||||
+	/* Amount of real data per full chunk */
 | 
			
		||||
+	unsigned int		chunk_size;
 | 
			
		||||
+
 | 
			
		||||
+	/* Amount of spare data per full chunk */
 | 
			
		||||
 	unsigned int		spare_size;
 | 
			
		||||
+
 | 
			
		||||
+	/* Number of full chunks (i.e chunk_size + spare_size) */
 | 
			
		||||
+	unsigned int            nfullchunks;
 | 
			
		||||
+
 | 
			
		||||
+	/*
 | 
			
		||||
+	 * Total number of chunks. If equal to nfullchunks, then there
 | 
			
		||||
+	 * are only full chunks. Otherwise, there is one last chunk of
 | 
			
		||||
+	 * size (last_chunk_size + last_spare_size)
 | 
			
		||||
+	 */
 | 
			
		||||
+	unsigned int            ntotalchunks;
 | 
			
		||||
+
 | 
			
		||||
+	/* Amount of real data in the last chunk */
 | 
			
		||||
+	unsigned int		last_chunk_size;
 | 
			
		||||
+
 | 
			
		||||
+	/* Amount of spare data in the last chunk */
 | 
			
		||||
+	unsigned int		last_spare_size;
 | 
			
		||||
+
 | 
			
		||||
 	unsigned int		ecc_size;
 | 
			
		||||
 	unsigned int		ecc_err_cnt;
 | 
			
		||||
 	unsigned int		max_bitflips;
 | 
			
		||||
 	int 			retcode;
 | 
			
		||||
 
 | 
			
		||||
+	/*
 | 
			
		||||
+	 * Variables only valid during command
 | 
			
		||||
+	 * execution. step_chunk_size and step_spare_size is the
 | 
			
		||||
+	 * amount of real data and spare data in the current
 | 
			
		||||
+	 * chunk. cur_chunk is the current chunk being
 | 
			
		||||
+	 * read/programmed.
 | 
			
		||||
+	 */
 | 
			
		||||
+	unsigned int		step_chunk_size;
 | 
			
		||||
+	unsigned int		step_spare_size;
 | 
			
		||||
+	unsigned int            cur_chunk;
 | 
			
		||||
+
 | 
			
		||||
 	/* cached register value */
 | 
			
		||||
 	uint32_t		reg_ndcr;
 | 
			
		||||
 	uint32_t		ndtr0cs0;
 | 
			
		||||
@@ -531,25 +560,6 @@ static int pxa3xx_nand_init(struct pxa3x
 | 
			
		||||
 	return 0;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
-/*
 | 
			
		||||
- * Set the data and OOB size, depending on the selected
 | 
			
		||||
- * spare and ECC configuration.
 | 
			
		||||
- * Only applicable to READ0, READOOB and PAGEPROG commands.
 | 
			
		||||
- */
 | 
			
		||||
-static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info,
 | 
			
		||||
-				struct mtd_info *mtd)
 | 
			
		||||
-{
 | 
			
		||||
-	int oob_enable = info->reg_ndcr & NDCR_SPARE_EN;
 | 
			
		||||
-
 | 
			
		||||
-	info->data_size = mtd->writesize;
 | 
			
		||||
-	if (!oob_enable)
 | 
			
		||||
-		return;
 | 
			
		||||
-
 | 
			
		||||
-	info->oob_size = info->spare_size;
 | 
			
		||||
-	if (!info->use_ecc)
 | 
			
		||||
-		info->oob_size += info->ecc_size;
 | 
			
		||||
-}
 | 
			
		||||
-
 | 
			
		||||
 /**
 | 
			
		||||
  * NOTE: it is a must to set ND_RUN firstly, then write
 | 
			
		||||
  * command buffer, otherwise, it does not work.
 | 
			
		||||
@@ -665,28 +675,28 @@ static void drain_fifo(struct pxa3xx_nan
 | 
			
		||||
 
 | 
			
		||||
 static void handle_data_pio(struct pxa3xx_nand_info *info)
 | 
			
		||||
 {
 | 
			
		||||
-	unsigned int do_bytes = min(info->data_size, info->chunk_size);
 | 
			
		||||
-
 | 
			
		||||
 	switch (info->state) {
 | 
			
		||||
 	case STATE_PIO_WRITING:
 | 
			
		||||
-		writesl(info->mmio_base + NDDB,
 | 
			
		||||
-			info->data_buff + info->data_buff_pos,
 | 
			
		||||
-			DIV_ROUND_UP(do_bytes, 4));
 | 
			
		||||
+		if (info->step_chunk_size)
 | 
			
		||||
+			writesl(info->mmio_base + NDDB,
 | 
			
		||||
+				info->data_buff + info->data_buff_pos,
 | 
			
		||||
+				DIV_ROUND_UP(info->step_chunk_size, 4));
 | 
			
		||||
 
 | 
			
		||||
-		if (info->oob_size > 0)
 | 
			
		||||
+		if (info->step_spare_size)
 | 
			
		||||
 			writesl(info->mmio_base + NDDB,
 | 
			
		||||
 				info->oob_buff + info->oob_buff_pos,
 | 
			
		||||
-				DIV_ROUND_UP(info->oob_size, 4));
 | 
			
		||||
+				DIV_ROUND_UP(info->step_spare_size, 4));
 | 
			
		||||
 		break;
 | 
			
		||||
 	case STATE_PIO_READING:
 | 
			
		||||
-		drain_fifo(info,
 | 
			
		||||
-			   info->data_buff + info->data_buff_pos,
 | 
			
		||||
-			   DIV_ROUND_UP(do_bytes, 4));
 | 
			
		||||
+		if (info->step_chunk_size)
 | 
			
		||||
+			drain_fifo(info,
 | 
			
		||||
+				   info->data_buff + info->data_buff_pos,
 | 
			
		||||
+				   DIV_ROUND_UP(info->step_chunk_size, 4));
 | 
			
		||||
 
 | 
			
		||||
-		if (info->oob_size > 0)
 | 
			
		||||
+		if (info->step_spare_size)
 | 
			
		||||
 			drain_fifo(info,
 | 
			
		||||
 				   info->oob_buff + info->oob_buff_pos,
 | 
			
		||||
-				   DIV_ROUND_UP(info->oob_size, 4));
 | 
			
		||||
+				   DIV_ROUND_UP(info->step_spare_size, 4));
 | 
			
		||||
 		break;
 | 
			
		||||
 	default:
 | 
			
		||||
 		dev_err(&info->pdev->dev, "%s: invalid state %d\n", __func__,
 | 
			
		||||
@@ -695,9 +705,8 @@ static void handle_data_pio(struct pxa3x
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
 	/* Update buffer pointers for multi-page read/write */
 | 
			
		||||
-	info->data_buff_pos += do_bytes;
 | 
			
		||||
-	info->oob_buff_pos += info->oob_size;
 | 
			
		||||
-	info->data_size -= do_bytes;
 | 
			
		||||
+	info->data_buff_pos += info->step_chunk_size;
 | 
			
		||||
+	info->oob_buff_pos += info->step_spare_size;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
 static void pxa3xx_nand_data_dma_irq(void *data)
 | 
			
		||||
@@ -738,8 +747,9 @@ static void start_data_dma(struct pxa3xx
 | 
			
		||||
 				info->state);
 | 
			
		||||
 		BUG();
 | 
			
		||||
 	}
 | 
			
		||||
-	info->sg.length = info->data_size +
 | 
			
		||||
-		(info->oob_size ? info->spare_size + info->ecc_size : 0);
 | 
			
		||||
+	info->sg.length = info->chunk_size;
 | 
			
		||||
+	if (info->use_spare)
 | 
			
		||||
+		info->sg.length += info->spare_size + info->ecc_size;
 | 
			
		||||
 	dma_map_sg(info->dma_chan->device->dev, &info->sg, 1, info->dma_dir);
 | 
			
		||||
 
 | 
			
		||||
 	tx = dmaengine_prep_slave_sg(info->dma_chan, &info->sg, 1, direction,
 | 
			
		||||
@@ -900,9 +910,11 @@ static void prepare_start_command(struct
 | 
			
		||||
 	/* reset data and oob column point to handle data */
 | 
			
		||||
 	info->buf_start		= 0;
 | 
			
		||||
 	info->buf_count		= 0;
 | 
			
		||||
-	info->oob_size		= 0;
 | 
			
		||||
 	info->data_buff_pos	= 0;
 | 
			
		||||
 	info->oob_buff_pos	= 0;
 | 
			
		||||
+	info->step_chunk_size   = 0;
 | 
			
		||||
+	info->step_spare_size   = 0;
 | 
			
		||||
+	info->cur_chunk         = 0;
 | 
			
		||||
 	info->use_ecc		= 0;
 | 
			
		||||
 	info->use_spare		= 1;
 | 
			
		||||
 	info->retcode		= ERR_NONE;
 | 
			
		||||
@@ -914,8 +926,6 @@ static void prepare_start_command(struct
 | 
			
		||||
 	case NAND_CMD_READ0:
 | 
			
		||||
 	case NAND_CMD_PAGEPROG:
 | 
			
		||||
 		info->use_ecc = 1;
 | 
			
		||||
-	case NAND_CMD_READOOB:
 | 
			
		||||
-		pxa3xx_set_datasize(info, mtd);
 | 
			
		||||
 		break;
 | 
			
		||||
 	case NAND_CMD_PARAM:
 | 
			
		||||
 		info->use_spare = 0;
 | 
			
		||||
@@ -974,6 +984,14 @@ static int prepare_set_command(struct px
 | 
			
		||||
 		if (command == NAND_CMD_READOOB)
 | 
			
		||||
 			info->buf_start += mtd->writesize;
 | 
			
		||||
 
 | 
			
		||||
+		if (info->cur_chunk < info->nfullchunks) {
 | 
			
		||||
+			info->step_chunk_size = info->chunk_size;
 | 
			
		||||
+			info->step_spare_size = info->spare_size;
 | 
			
		||||
+		} else {
 | 
			
		||||
+			info->step_chunk_size = info->last_chunk_size;
 | 
			
		||||
+			info->step_spare_size = info->last_spare_size;
 | 
			
		||||
+		}
 | 
			
		||||
+
 | 
			
		||||
 		/*
 | 
			
		||||
 		 * Multiple page read needs an 'extended command type' field,
 | 
			
		||||
 		 * which is either naked-read or last-read according to the
 | 
			
		||||
@@ -985,8 +1003,8 @@ static int prepare_set_command(struct px
 | 
			
		||||
 			info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8)
 | 
			
		||||
 					| NDCB0_LEN_OVRD
 | 
			
		||||
 					| NDCB0_EXT_CMD_TYPE(ext_cmd_type);
 | 
			
		||||
-			info->ndcb3 = info->chunk_size +
 | 
			
		||||
-				      info->oob_size;
 | 
			
		||||
+			info->ndcb3 = info->step_chunk_size +
 | 
			
		||||
+				info->step_spare_size;
 | 
			
		||||
 		}
 | 
			
		||||
 
 | 
			
		||||
 		set_command_address(info, mtd->writesize, column, page_addr);
 | 
			
		||||
@@ -1006,8 +1024,6 @@ static int prepare_set_command(struct px
 | 
			
		||||
 				| NDCB0_EXT_CMD_TYPE(ext_cmd_type)
 | 
			
		||||
 				| addr_cycle
 | 
			
		||||
 				| command;
 | 
			
		||||
-			/* No data transfer in this case */
 | 
			
		||||
-			info->data_size = 0;
 | 
			
		||||
 			exec_cmd = 1;
 | 
			
		||||
 		}
 | 
			
		||||
 		break;
 | 
			
		||||
@@ -1019,6 +1035,14 @@ static int prepare_set_command(struct px
 | 
			
		||||
 			break;
 | 
			
		||||
 		}
 | 
			
		||||
 
 | 
			
		||||
+		if (info->cur_chunk < info->nfullchunks) {
 | 
			
		||||
+			info->step_chunk_size = info->chunk_size;
 | 
			
		||||
+			info->step_spare_size = info->spare_size;
 | 
			
		||||
+		} else {
 | 
			
		||||
+			info->step_chunk_size = info->last_chunk_size;
 | 
			
		||||
+			info->step_spare_size = info->last_spare_size;
 | 
			
		||||
+		}
 | 
			
		||||
+
 | 
			
		||||
 		/* Second command setting for large pages */
 | 
			
		||||
 		if (mtd->writesize > PAGE_CHUNK_SIZE) {
 | 
			
		||||
 			/*
 | 
			
		||||
@@ -1029,14 +1053,14 @@ static int prepare_set_command(struct px
 | 
			
		||||
 			info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
 | 
			
		||||
 					| NDCB0_LEN_OVRD
 | 
			
		||||
 					| NDCB0_EXT_CMD_TYPE(ext_cmd_type);
 | 
			
		||||
-			info->ndcb3 = info->chunk_size +
 | 
			
		||||
-				      info->oob_size;
 | 
			
		||||
+			info->ndcb3 = info->step_chunk_size +
 | 
			
		||||
+				      info->step_spare_size;
 | 
			
		||||
 
 | 
			
		||||
 			/*
 | 
			
		||||
 			 * This is the command dispatch that completes a chunked
 | 
			
		||||
 			 * page program operation.
 | 
			
		||||
 			 */
 | 
			
		||||
-			if (info->data_size == 0) {
 | 
			
		||||
+			if (info->cur_chunk == info->ntotalchunks) {
 | 
			
		||||
 				info->ndcb0 = NDCB0_CMD_TYPE(0x1)
 | 
			
		||||
 					| NDCB0_EXT_CMD_TYPE(ext_cmd_type)
 | 
			
		||||
 					| command;
 | 
			
		||||
@@ -1063,7 +1087,7 @@ static int prepare_set_command(struct px
 | 
			
		||||
 				| command;
 | 
			
		||||
 		info->ndcb1 = (column & 0xFF);
 | 
			
		||||
 		info->ndcb3 = INIT_BUFFER_SIZE;
 | 
			
		||||
-		info->data_size = INIT_BUFFER_SIZE;
 | 
			
		||||
+		info->step_chunk_size = INIT_BUFFER_SIZE;
 | 
			
		||||
 		break;
 | 
			
		||||
 
 | 
			
		||||
 	case NAND_CMD_READID:
 | 
			
		||||
@@ -1073,7 +1097,7 @@ static int prepare_set_command(struct px
 | 
			
		||||
 				| command;
 | 
			
		||||
 		info->ndcb1 = (column & 0xFF);
 | 
			
		||||
 
 | 
			
		||||
-		info->data_size = 8;
 | 
			
		||||
+		info->step_chunk_size = 8;
 | 
			
		||||
 		break;
 | 
			
		||||
 	case NAND_CMD_STATUS:
 | 
			
		||||
 		info->buf_count = 1;
 | 
			
		||||
@@ -1081,7 +1105,7 @@ static int prepare_set_command(struct px
 | 
			
		||||
 				| NDCB0_ADDR_CYC(1)
 | 
			
		||||
 				| command;
 | 
			
		||||
 
 | 
			
		||||
-		info->data_size = 8;
 | 
			
		||||
+		info->step_chunk_size = 8;
 | 
			
		||||
 		break;
 | 
			
		||||
 
 | 
			
		||||
 	case NAND_CMD_ERASE1:
 | 
			
		||||
@@ -1220,6 +1244,7 @@ static void nand_cmdfunc_extended(struct
 | 
			
		||||
 	init_completion(&info->dev_ready);
 | 
			
		||||
 	do {
 | 
			
		||||
 		info->state = STATE_PREPARED;
 | 
			
		||||
+
 | 
			
		||||
 		exec_cmd = prepare_set_command(info, command, ext_cmd_type,
 | 
			
		||||
 					       column, page_addr);
 | 
			
		||||
 		if (!exec_cmd) {
 | 
			
		||||
@@ -1239,22 +1264,30 @@ static void nand_cmdfunc_extended(struct
 | 
			
		||||
 			break;
 | 
			
		||||
 		}
 | 
			
		||||
 
 | 
			
		||||
+		/* Only a few commands need several steps */
 | 
			
		||||
+		if (command != NAND_CMD_PAGEPROG &&
 | 
			
		||||
+		    command != NAND_CMD_READ0    &&
 | 
			
		||||
+		    command != NAND_CMD_READOOB)
 | 
			
		||||
+			break;
 | 
			
		||||
+
 | 
			
		||||
+		info->cur_chunk++;
 | 
			
		||||
+
 | 
			
		||||
 		/* Check if the sequence is complete */
 | 
			
		||||
-		if (info->data_size == 0 && command != NAND_CMD_PAGEPROG)
 | 
			
		||||
+		if (info->cur_chunk == info->ntotalchunks && command != NAND_CMD_PAGEPROG)
 | 
			
		||||
 			break;
 | 
			
		||||
 
 | 
			
		||||
 		/*
 | 
			
		||||
 		 * After a splitted program command sequence has issued
 | 
			
		||||
 		 * the command dispatch, the command sequence is complete.
 | 
			
		||||
 		 */
 | 
			
		||||
-		if (info->data_size == 0 &&
 | 
			
		||||
+		if (info->cur_chunk == (info->ntotalchunks + 1) &&
 | 
			
		||||
 		    command == NAND_CMD_PAGEPROG &&
 | 
			
		||||
 		    ext_cmd_type == EXT_CMD_TYPE_DISPATCH)
 | 
			
		||||
 			break;
 | 
			
		||||
 
 | 
			
		||||
 		if (command == NAND_CMD_READ0 || command == NAND_CMD_READOOB) {
 | 
			
		||||
 			/* Last read: issue a 'last naked read' */
 | 
			
		||||
-			if (info->data_size == info->chunk_size)
 | 
			
		||||
+			if (info->cur_chunk == info->ntotalchunks - 1)
 | 
			
		||||
 				ext_cmd_type = EXT_CMD_TYPE_LAST_RW;
 | 
			
		||||
 			else
 | 
			
		||||
 				ext_cmd_type = EXT_CMD_TYPE_NAKED_RW;
 | 
			
		||||
@@ -1264,7 +1297,7 @@ static void nand_cmdfunc_extended(struct
 | 
			
		||||
 		 * the command dispatch must be issued to complete.
 | 
			
		||||
 		 */
 | 
			
		||||
 		} else if (command == NAND_CMD_PAGEPROG &&
 | 
			
		||||
-			   info->data_size == 0) {
 | 
			
		||||
+			   info->cur_chunk == info->ntotalchunks) {
 | 
			
		||||
 				ext_cmd_type = EXT_CMD_TYPE_DISPATCH;
 | 
			
		||||
 		}
 | 
			
		||||
 	} while (1);
 | 
			
		||||
@@ -1514,6 +1547,8 @@ static int pxa_ecc_init(struct pxa3xx_na
 | 
			
		||||
 			int strength, int ecc_stepsize, int page_size)
 | 
			
		||||
 {
 | 
			
		||||
 	if (strength == 1 && ecc_stepsize == 512 && page_size == 2048) {
 | 
			
		||||
+		info->nfullchunks = 1;
 | 
			
		||||
+		info->ntotalchunks = 1;
 | 
			
		||||
 		info->chunk_size = 2048;
 | 
			
		||||
 		info->spare_size = 40;
 | 
			
		||||
 		info->ecc_size = 24;
 | 
			
		||||
@@ -1522,6 +1557,8 @@ static int pxa_ecc_init(struct pxa3xx_na
 | 
			
		||||
 		ecc->strength = 1;
 | 
			
		||||
 
 | 
			
		||||
 	} else if (strength == 1 && ecc_stepsize == 512 && page_size == 512) {
 | 
			
		||||
+		info->nfullchunks = 1;
 | 
			
		||||
+		info->ntotalchunks = 1;
 | 
			
		||||
 		info->chunk_size = 512;
 | 
			
		||||
 		info->spare_size = 8;
 | 
			
		||||
 		info->ecc_size = 8;
 | 
			
		||||
@@ -1535,6 +1572,8 @@ static int pxa_ecc_init(struct pxa3xx_na
 | 
			
		||||
 	 */
 | 
			
		||||
 	} else if (strength == 4 && ecc_stepsize == 512 && page_size == 2048) {
 | 
			
		||||
 		info->ecc_bch = 1;
 | 
			
		||||
+		info->nfullchunks = 1;
 | 
			
		||||
+		info->ntotalchunks = 1;
 | 
			
		||||
 		info->chunk_size = 2048;
 | 
			
		||||
 		info->spare_size = 32;
 | 
			
		||||
 		info->ecc_size = 32;
 | 
			
		||||
@@ -1545,6 +1584,8 @@ static int pxa_ecc_init(struct pxa3xx_na
 | 
			
		||||
 
 | 
			
		||||
 	} else if (strength == 4 && ecc_stepsize == 512 && page_size == 4096) {
 | 
			
		||||
 		info->ecc_bch = 1;
 | 
			
		||||
+		info->nfullchunks = 2;
 | 
			
		||||
+		info->ntotalchunks = 2;
 | 
			
		||||
 		info->chunk_size = 2048;
 | 
			
		||||
 		info->spare_size = 32;
 | 
			
		||||
 		info->ecc_size = 32;
 | 
			
		||||
@@ -1559,8 +1600,12 @@ static int pxa_ecc_init(struct pxa3xx_na
 | 
			
		||||
 	 */
 | 
			
		||||
 	} else if (strength == 8 && ecc_stepsize == 512 && page_size == 4096) {
 | 
			
		||||
 		info->ecc_bch = 1;
 | 
			
		||||
+		info->nfullchunks = 4;
 | 
			
		||||
+		info->ntotalchunks = 5;
 | 
			
		||||
 		info->chunk_size = 1024;
 | 
			
		||||
 		info->spare_size = 0;
 | 
			
		||||
+		info->last_chunk_size = 0;
 | 
			
		||||
+		info->last_spare_size = 64;
 | 
			
		||||
 		info->ecc_size = 32;
 | 
			
		||||
 		ecc->mode = NAND_ECC_HW;
 | 
			
		||||
 		ecc->size = info->chunk_size;
 | 
			
		||||
@@ -0,0 +1,42 @@
 | 
			
		||||
From: =?UTF-8?q?Ezequiel=20Garc=C3=ADa?= <ezequiel@vanguardiasur.com.ar>
 | 
			
		||||
Date: Wed, 4 Nov 2015 13:13:41 -0300
 | 
			
		||||
Subject: [PATCH] mtd: pxa3xx_nand: Increase the initial chunk size
 | 
			
		||||
 | 
			
		||||
The chunk size represents the size of the data chunks, which
 | 
			
		||||
is used by the controllers that allow to split transfered data.
 | 
			
		||||
 | 
			
		||||
However, the initial chunk size is used in a non-splitted way,
 | 
			
		||||
during device identification. Therefore, it must be large enough
 | 
			
		||||
for all the NAND commands issued during device identification.
 | 
			
		||||
This includes NAND_CMD_PARAM which was recently changed to
 | 
			
		||||
transfer up to 2048 bytes (for the redundant parameter pages).
 | 
			
		||||
 | 
			
		||||
Thus, the initial chunk size should be 2048 as well.
 | 
			
		||||
 | 
			
		||||
On Armada 370/XP platforms (NFCv2) booted without the keep-config
 | 
			
		||||
devicetree property, this commit fixes a timeout on the NAND_CMD_PARAM
 | 
			
		||||
command:
 | 
			
		||||
 | 
			
		||||
  [..]
 | 
			
		||||
  pxa3xx-nand f10d0000.nand: This platform can't do DMA on this device
 | 
			
		||||
  pxa3xx-nand f10d0000.nand: Wait time out!!!
 | 
			
		||||
  nand: device found, Manufacturer ID: 0x2c, Chip ID: 0x38
 | 
			
		||||
  nand: Micron MT29F8G08ABABAWP
 | 
			
		||||
  nand: 1024 MiB, SLC, erase size: 512 KiB, page size: 4096, OOB size: 224
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
 | 
			
		||||
Acked-by: Robert Jarzmik <robert.jarzmik@free.fr>
 | 
			
		||||
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
--- a/drivers/mtd/nand/pxa3xx_nand.c
 | 
			
		||||
+++ b/drivers/mtd/nand/pxa3xx_nand.c
 | 
			
		||||
@@ -1637,7 +1637,7 @@ static int pxa3xx_nand_scan(struct mtd_i
 | 
			
		||||
 		goto KEEP_CONFIG;
 | 
			
		||||
 
 | 
			
		||||
 	/* Set a default chunk size */
 | 
			
		||||
-	info->chunk_size = 512;
 | 
			
		||||
+	info->chunk_size = PAGE_CHUNK_SIZE;
 | 
			
		||||
 
 | 
			
		||||
 	ret = pxa3xx_nand_config_flash(info);
 | 
			
		||||
 	if (ret)
 | 
			
		||||
@@ -0,0 +1,104 @@
 | 
			
		||||
From: =?UTF-8?q?Ezequiel=20Garc=C3=ADa?= <ezequiel@vanguardiasur.com.ar>
 | 
			
		||||
Date: Wed, 4 Nov 2015 13:13:42 -0300
 | 
			
		||||
Subject: [PATCH] mtd: pxa3xx_nand: Fix initial controller configuration
 | 
			
		||||
 | 
			
		||||
The Data Flash Control Register (NDCR) contains two types
 | 
			
		||||
of parameters: those that are needed for device identification,
 | 
			
		||||
and those that can only be set after device identification.
 | 
			
		||||
 | 
			
		||||
Therefore, the driver can't set them all at once and instead
 | 
			
		||||
needs to configure the first group before nand_scan_ident()
 | 
			
		||||
and the second group later.
 | 
			
		||||
 | 
			
		||||
Let's split pxa3xx_nand_config in two halves, and set the
 | 
			
		||||
parameters that depend on the device geometry once this is known.
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
 | 
			
		||||
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
--- a/drivers/mtd/nand/pxa3xx_nand.c
 | 
			
		||||
+++ b/drivers/mtd/nand/pxa3xx_nand.c
 | 
			
		||||
@@ -1420,34 +1420,43 @@ static int pxa3xx_nand_waitfunc(struct m
 | 
			
		||||
 	return NAND_STATUS_READY;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
-static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info)
 | 
			
		||||
+static int pxa3xx_nand_config_ident(struct pxa3xx_nand_info *info)
 | 
			
		||||
 {
 | 
			
		||||
 	struct platform_device *pdev = info->pdev;
 | 
			
		||||
 	struct pxa3xx_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
 | 
			
		||||
-	struct pxa3xx_nand_host *host = info->host[info->cs];
 | 
			
		||||
-	struct mtd_info *mtd = host->mtd;
 | 
			
		||||
-	struct nand_chip *chip = mtd->priv;
 | 
			
		||||
 
 | 
			
		||||
-	/* configure default flash values */
 | 
			
		||||
+	/* Configure default flash values */
 | 
			
		||||
+	info->chunk_size = PAGE_CHUNK_SIZE;
 | 
			
		||||
 	info->reg_ndcr = 0x0; /* enable all interrupts */
 | 
			
		||||
 	info->reg_ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0;
 | 
			
		||||
 	info->reg_ndcr |= NDCR_RD_ID_CNT(READ_ID_BYTES);
 | 
			
		||||
-	info->reg_ndcr |= NDCR_SPARE_EN; /* enable spare by default */
 | 
			
		||||
+	info->reg_ndcr |= NDCR_SPARE_EN;
 | 
			
		||||
+
 | 
			
		||||
+	return 0;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static void pxa3xx_nand_config_tail(struct pxa3xx_nand_info *info)
 | 
			
		||||
+{
 | 
			
		||||
+	struct pxa3xx_nand_host *host = info->host[info->cs];
 | 
			
		||||
+	struct mtd_info *mtd = host->mtd;
 | 
			
		||||
+	struct nand_chip *chip = mtd->priv;
 | 
			
		||||
+
 | 
			
		||||
 	info->reg_ndcr |= (host->col_addr_cycles == 2) ? NDCR_RA_START : 0;
 | 
			
		||||
 	info->reg_ndcr |= (chip->page_shift == 6) ? NDCR_PG_PER_BLK : 0;
 | 
			
		||||
 	info->reg_ndcr |= (mtd->writesize == 2048) ? NDCR_PAGE_SZ : 0;
 | 
			
		||||
-
 | 
			
		||||
-	return 0;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
 static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info)
 | 
			
		||||
 {
 | 
			
		||||
+	struct platform_device *pdev = info->pdev;
 | 
			
		||||
+	struct pxa3xx_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
 | 
			
		||||
 	uint32_t ndcr = nand_readl(info, NDCR);
 | 
			
		||||
 
 | 
			
		||||
 	/* Set an initial chunk size */
 | 
			
		||||
 	info->chunk_size = ndcr & NDCR_PAGE_SZ ? 2048 : 512;
 | 
			
		||||
 	info->reg_ndcr = ndcr &
 | 
			
		||||
 		~(NDCR_INT_MASK | NDCR_ND_ARB_EN | NFCV1_NDCR_ARB_CNTL);
 | 
			
		||||
+	info->reg_ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0;
 | 
			
		||||
 	info->ndtr0cs0 = nand_readl(info, NDTR0CS0);
 | 
			
		||||
 	info->ndtr1cs0 = nand_readl(info, NDTR1CS0);
 | 
			
		||||
 	return 0;
 | 
			
		||||
@@ -1636,10 +1645,7 @@ static int pxa3xx_nand_scan(struct mtd_i
 | 
			
		||||
 	if (pdata->keep_config && !pxa3xx_nand_detect_config(info))
 | 
			
		||||
 		goto KEEP_CONFIG;
 | 
			
		||||
 
 | 
			
		||||
-	/* Set a default chunk size */
 | 
			
		||||
-	info->chunk_size = PAGE_CHUNK_SIZE;
 | 
			
		||||
-
 | 
			
		||||
-	ret = pxa3xx_nand_config_flash(info);
 | 
			
		||||
+	ret = pxa3xx_nand_config_ident(info);
 | 
			
		||||
 	if (ret)
 | 
			
		||||
 		return ret;
 | 
			
		||||
 
 | 
			
		||||
@@ -1652,7 +1658,6 @@ static int pxa3xx_nand_scan(struct mtd_i
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
 KEEP_CONFIG:
 | 
			
		||||
-	info->reg_ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0;
 | 
			
		||||
 	if (info->reg_ndcr & NDCR_DWIDTH_M)
 | 
			
		||||
 		chip->options |= NAND_BUSWIDTH_16;
 | 
			
		||||
 
 | 
			
		||||
@@ -1737,6 +1742,10 @@ KEEP_CONFIG:
 | 
			
		||||
 		host->row_addr_cycles = 3;
 | 
			
		||||
 	else
 | 
			
		||||
 		host->row_addr_cycles = 2;
 | 
			
		||||
+
 | 
			
		||||
+	if (!pdata->keep_config)
 | 
			
		||||
+		pxa3xx_nand_config_tail(info);
 | 
			
		||||
+
 | 
			
		||||
 	return nand_scan_tail(mtd);
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,94 @@
 | 
			
		||||
From: Marcin Wojtas <mw@semihalf.com>
 | 
			
		||||
Date: Mon, 14 Mar 2016 09:39:02 +0100
 | 
			
		||||
Subject: [PATCH] bus: mvebu-mbus: provide api for obtaining IO and DRAM window
 | 
			
		||||
 information
 | 
			
		||||
 | 
			
		||||
This commit enables finding appropriate mbus window and obtaining its
 | 
			
		||||
target id and attribute for given physical address in two separate
 | 
			
		||||
routines, both for IO and DRAM windows. This functionality
 | 
			
		||||
is needed for Armada XP/38x Network Controller's Buffer Manager and
 | 
			
		||||
PnC configuration.
 | 
			
		||||
 | 
			
		||||
[gregory.clement@free-electrons.com: Fix size test for
 | 
			
		||||
mvebu_mbus_get_dram_win_info]
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
 | 
			
		||||
[DRAM window information reference in LKv3.10]
 | 
			
		||||
Signed-off-by: Evan Wang <xswang@marvell.com>
 | 
			
		||||
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
 | 
			
		||||
Signed-off-by: David S. Miller <davem@davemloft.net>
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
--- a/drivers/bus/mvebu-mbus.c
 | 
			
		||||
+++ b/drivers/bus/mvebu-mbus.c
 | 
			
		||||
@@ -948,6 +948,58 @@ void mvebu_mbus_get_pcie_io_aperture(str
 | 
			
		||||
 	*res = mbus_state.pcie_io_aperture;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
+int mvebu_mbus_get_dram_win_info(phys_addr_t phyaddr, u8 *target, u8 *attr)
 | 
			
		||||
+{
 | 
			
		||||
+	const struct mbus_dram_target_info *dram;
 | 
			
		||||
+	int i;
 | 
			
		||||
+
 | 
			
		||||
+	/* Get dram info */
 | 
			
		||||
+	dram = mv_mbus_dram_info();
 | 
			
		||||
+	if (!dram) {
 | 
			
		||||
+		pr_err("missing DRAM information\n");
 | 
			
		||||
+		return -ENODEV;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	/* Try to find matching DRAM window for phyaddr */
 | 
			
		||||
+	for (i = 0; i < dram->num_cs; i++) {
 | 
			
		||||
+		const struct mbus_dram_window *cs = dram->cs + i;
 | 
			
		||||
+
 | 
			
		||||
+		if (cs->base <= phyaddr &&
 | 
			
		||||
+			phyaddr <= (cs->base + cs->size - 1)) {
 | 
			
		||||
+			*target = dram->mbus_dram_target_id;
 | 
			
		||||
+			*attr = cs->mbus_attr;
 | 
			
		||||
+			return 0;
 | 
			
		||||
+		}
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	pr_err("invalid dram address 0x%x\n", phyaddr);
 | 
			
		||||
+	return -EINVAL;
 | 
			
		||||
+}
 | 
			
		||||
+EXPORT_SYMBOL_GPL(mvebu_mbus_get_dram_win_info);
 | 
			
		||||
+
 | 
			
		||||
+int mvebu_mbus_get_io_win_info(phys_addr_t phyaddr, u32 *size, u8 *target,
 | 
			
		||||
+			       u8 *attr)
 | 
			
		||||
+{
 | 
			
		||||
+	int win;
 | 
			
		||||
+
 | 
			
		||||
+	for (win = 0; win < mbus_state.soc->num_wins; win++) {
 | 
			
		||||
+		u64 wbase;
 | 
			
		||||
+		int enabled;
 | 
			
		||||
+
 | 
			
		||||
+		mvebu_mbus_read_window(&mbus_state, win, &enabled, &wbase,
 | 
			
		||||
+				       size, target, attr, NULL);
 | 
			
		||||
+
 | 
			
		||||
+		if (!enabled)
 | 
			
		||||
+			continue;
 | 
			
		||||
+
 | 
			
		||||
+		if (wbase <= phyaddr && phyaddr <= wbase + *size)
 | 
			
		||||
+			return win;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	return -EINVAL;
 | 
			
		||||
+}
 | 
			
		||||
+EXPORT_SYMBOL_GPL(mvebu_mbus_get_io_win_info);
 | 
			
		||||
+
 | 
			
		||||
 static __init int mvebu_mbus_debugfs_init(void)
 | 
			
		||||
 {
 | 
			
		||||
 	struct mvebu_mbus_state *s = &mbus_state;
 | 
			
		||||
--- a/include/linux/mbus.h
 | 
			
		||||
+++ b/include/linux/mbus.h
 | 
			
		||||
@@ -69,6 +69,9 @@ static inline const struct mbus_dram_tar
 | 
			
		||||
 int mvebu_mbus_save_cpu_target(u32 *store_addr);
 | 
			
		||||
 void mvebu_mbus_get_pcie_mem_aperture(struct resource *res);
 | 
			
		||||
 void mvebu_mbus_get_pcie_io_aperture(struct resource *res);
 | 
			
		||||
+int mvebu_mbus_get_dram_win_info(phys_addr_t phyaddr, u8 *target, u8 *attr);
 | 
			
		||||
+int mvebu_mbus_get_io_win_info(phys_addr_t phyaddr, u32 *size, u8 *target,
 | 
			
		||||
+			       u8 *attr);
 | 
			
		||||
 int mvebu_mbus_add_window_remap_by_id(unsigned int target,
 | 
			
		||||
 				      unsigned int attribute,
 | 
			
		||||
 				      phys_addr_t base, size_t size,
 | 
			
		||||
@@ -0,0 +1,55 @@
 | 
			
		||||
From: Stas Sergeev <stsp@list.ru>
 | 
			
		||||
Date: Wed, 2 Dec 2015 20:33:56 +0300
 | 
			
		||||
Subject: [PATCH] mvneta: consolidate autoneg enabling
 | 
			
		||||
 | 
			
		||||
This moves autoneg-related bit manipulations to the single place.
 | 
			
		||||
 | 
			
		||||
CC: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
 | 
			
		||||
CC: netdev@vger.kernel.org
 | 
			
		||||
CC: linux-kernel@vger.kernel.org
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Stas Sergeev <stsp@users.sourceforge.net>
 | 
			
		||||
Signed-off-by: David S. Miller <davem@davemloft.net>
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
+++ b/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
@@ -1067,15 +1067,28 @@ static void mvneta_defaults_set(struct m
 | 
			
		||||
 		       MVNETA_GMAC_AN_SPEED_EN |
 | 
			
		||||
 		       MVNETA_GMAC_AN_DUPLEX_EN;
 | 
			
		||||
 		mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val);
 | 
			
		||||
+
 | 
			
		||||
 		val = mvreg_read(pp, MVNETA_GMAC_CLOCK_DIVIDER);
 | 
			
		||||
 		val |= MVNETA_GMAC_1MS_CLOCK_ENABLE;
 | 
			
		||||
 		mvreg_write(pp, MVNETA_GMAC_CLOCK_DIVIDER, val);
 | 
			
		||||
+
 | 
			
		||||
+		val = mvreg_read(pp, MVNETA_GMAC_CTRL_2);
 | 
			
		||||
+		val |= MVNETA_GMAC2_INBAND_AN_ENABLE;
 | 
			
		||||
+		mvreg_write(pp, MVNETA_GMAC_CTRL_2, val);
 | 
			
		||||
 	} else {
 | 
			
		||||
 		val = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG);
 | 
			
		||||
 		val &= ~(MVNETA_GMAC_INBAND_AN_ENABLE |
 | 
			
		||||
 		       MVNETA_GMAC_AN_SPEED_EN |
 | 
			
		||||
 		       MVNETA_GMAC_AN_DUPLEX_EN);
 | 
			
		||||
 		mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val);
 | 
			
		||||
+
 | 
			
		||||
+		val = mvreg_read(pp, MVNETA_GMAC_CLOCK_DIVIDER);
 | 
			
		||||
+		val &= ~MVNETA_GMAC_1MS_CLOCK_ENABLE;
 | 
			
		||||
+		mvreg_write(pp, MVNETA_GMAC_CLOCK_DIVIDER, val);
 | 
			
		||||
+
 | 
			
		||||
+		val = mvreg_read(pp, MVNETA_GMAC_CTRL_2);
 | 
			
		||||
+		val &= ~MVNETA_GMAC2_INBAND_AN_ENABLE;
 | 
			
		||||
+		mvreg_write(pp, MVNETA_GMAC_CTRL_2, val);
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
 	mvneta_set_ucast_table(pp, -1);
 | 
			
		||||
@@ -3230,9 +3243,6 @@ static int mvneta_port_power_up(struct m
 | 
			
		||||
 		return -EINVAL;
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
-	if (pp->use_inband_status)
 | 
			
		||||
-		ctrl |= MVNETA_GMAC2_INBAND_AN_ENABLE;
 | 
			
		||||
-
 | 
			
		||||
 	/* Cancel Port Reset */
 | 
			
		||||
 	ctrl &= ~MVNETA_GMAC2_PORT_RESET;
 | 
			
		||||
 	mvreg_write(pp, MVNETA_GMAC_CTRL_2, ctrl);
 | 
			
		||||
@@ -0,0 +1,165 @@
 | 
			
		||||
From: Stas Sergeev <stsp@list.ru>
 | 
			
		||||
Date: Wed, 2 Dec 2015 20:35:11 +0300
 | 
			
		||||
Subject: [PATCH] mvneta: implement ethtool autonegotiation control
 | 
			
		||||
 | 
			
		||||
This patch allows to do
 | 
			
		||||
ethtool -s eth0 autoneg off
 | 
			
		||||
ethtool -s eth0 autoneg on
 | 
			
		||||
to disable or enable autonegotiation at run-time.
 | 
			
		||||
Without that functionality, the only way to control the autonegotiation
 | 
			
		||||
is to modify the device tree.
 | 
			
		||||
 | 
			
		||||
This is needed if you plan to use the same kernel with
 | 
			
		||||
different ethernet switches, the ones that support the in-band
 | 
			
		||||
status and the ones that not.
 | 
			
		||||
 | 
			
		||||
CC: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
 | 
			
		||||
CC: netdev@vger.kernel.org
 | 
			
		||||
CC: linux-kernel@vger.kernel.org
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Stas Sergeev <stsp@users.sourceforge.net>
 | 
			
		||||
Signed-off-by: David S. Miller <davem@davemloft.net>
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
+++ b/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
@@ -371,7 +371,7 @@ struct mvneta_port {
 | 
			
		||||
 	unsigned int duplex;
 | 
			
		||||
 	unsigned int speed;
 | 
			
		||||
 	unsigned int tx_csum_limit;
 | 
			
		||||
-	int use_inband_status:1;
 | 
			
		||||
+	unsigned int use_inband_status:1;
 | 
			
		||||
 
 | 
			
		||||
 	u64 ethtool_stats[ARRAY_SIZE(mvneta_statistics)];
 | 
			
		||||
 };
 | 
			
		||||
@@ -973,6 +973,44 @@ static void mvneta_set_other_mcast_table
 | 
			
		||||
 		mvreg_write(pp, MVNETA_DA_FILT_OTH_MCAST + offset, val);
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
+static void mvneta_set_autoneg(struct mvneta_port *pp, int enable)
 | 
			
		||||
+{
 | 
			
		||||
+	u32 val;
 | 
			
		||||
+
 | 
			
		||||
+	if (enable) {
 | 
			
		||||
+		val = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG);
 | 
			
		||||
+		val &= ~(MVNETA_GMAC_FORCE_LINK_PASS |
 | 
			
		||||
+			 MVNETA_GMAC_FORCE_LINK_DOWN |
 | 
			
		||||
+			 MVNETA_GMAC_AN_FLOW_CTRL_EN);
 | 
			
		||||
+		val |= MVNETA_GMAC_INBAND_AN_ENABLE |
 | 
			
		||||
+		       MVNETA_GMAC_AN_SPEED_EN |
 | 
			
		||||
+		       MVNETA_GMAC_AN_DUPLEX_EN;
 | 
			
		||||
+		mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val);
 | 
			
		||||
+
 | 
			
		||||
+		val = mvreg_read(pp, MVNETA_GMAC_CLOCK_DIVIDER);
 | 
			
		||||
+		val |= MVNETA_GMAC_1MS_CLOCK_ENABLE;
 | 
			
		||||
+		mvreg_write(pp, MVNETA_GMAC_CLOCK_DIVIDER, val);
 | 
			
		||||
+
 | 
			
		||||
+		val = mvreg_read(pp, MVNETA_GMAC_CTRL_2);
 | 
			
		||||
+		val |= MVNETA_GMAC2_INBAND_AN_ENABLE;
 | 
			
		||||
+		mvreg_write(pp, MVNETA_GMAC_CTRL_2, val);
 | 
			
		||||
+	} else {
 | 
			
		||||
+		val = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG);
 | 
			
		||||
+		val &= ~(MVNETA_GMAC_INBAND_AN_ENABLE |
 | 
			
		||||
+		       MVNETA_GMAC_AN_SPEED_EN |
 | 
			
		||||
+		       MVNETA_GMAC_AN_DUPLEX_EN);
 | 
			
		||||
+		mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val);
 | 
			
		||||
+
 | 
			
		||||
+		val = mvreg_read(pp, MVNETA_GMAC_CLOCK_DIVIDER);
 | 
			
		||||
+		val &= ~MVNETA_GMAC_1MS_CLOCK_ENABLE;
 | 
			
		||||
+		mvreg_write(pp, MVNETA_GMAC_CLOCK_DIVIDER, val);
 | 
			
		||||
+
 | 
			
		||||
+		val = mvreg_read(pp, MVNETA_GMAC_CTRL_2);
 | 
			
		||||
+		val &= ~MVNETA_GMAC2_INBAND_AN_ENABLE;
 | 
			
		||||
+		mvreg_write(pp, MVNETA_GMAC_CTRL_2, val);
 | 
			
		||||
+	}
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
 /* This method sets defaults to the NETA port:
 | 
			
		||||
  *	Clears interrupt Cause and Mask registers.
 | 
			
		||||
  *	Clears all MAC tables.
 | 
			
		||||
@@ -1058,39 +1096,7 @@ static void mvneta_defaults_set(struct m
 | 
			
		||||
 	val &= ~MVNETA_PHY_POLLING_ENABLE;
 | 
			
		||||
 	mvreg_write(pp, MVNETA_UNIT_CONTROL, val);
 | 
			
		||||
 
 | 
			
		||||
-	if (pp->use_inband_status) {
 | 
			
		||||
-		val = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG);
 | 
			
		||||
-		val &= ~(MVNETA_GMAC_FORCE_LINK_PASS |
 | 
			
		||||
-			 MVNETA_GMAC_FORCE_LINK_DOWN |
 | 
			
		||||
-			 MVNETA_GMAC_AN_FLOW_CTRL_EN);
 | 
			
		||||
-		val |= MVNETA_GMAC_INBAND_AN_ENABLE |
 | 
			
		||||
-		       MVNETA_GMAC_AN_SPEED_EN |
 | 
			
		||||
-		       MVNETA_GMAC_AN_DUPLEX_EN;
 | 
			
		||||
-		mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val);
 | 
			
		||||
-
 | 
			
		||||
-		val = mvreg_read(pp, MVNETA_GMAC_CLOCK_DIVIDER);
 | 
			
		||||
-		val |= MVNETA_GMAC_1MS_CLOCK_ENABLE;
 | 
			
		||||
-		mvreg_write(pp, MVNETA_GMAC_CLOCK_DIVIDER, val);
 | 
			
		||||
-
 | 
			
		||||
-		val = mvreg_read(pp, MVNETA_GMAC_CTRL_2);
 | 
			
		||||
-		val |= MVNETA_GMAC2_INBAND_AN_ENABLE;
 | 
			
		||||
-		mvreg_write(pp, MVNETA_GMAC_CTRL_2, val);
 | 
			
		||||
-	} else {
 | 
			
		||||
-		val = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG);
 | 
			
		||||
-		val &= ~(MVNETA_GMAC_INBAND_AN_ENABLE |
 | 
			
		||||
-		       MVNETA_GMAC_AN_SPEED_EN |
 | 
			
		||||
-		       MVNETA_GMAC_AN_DUPLEX_EN);
 | 
			
		||||
-		mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val);
 | 
			
		||||
-
 | 
			
		||||
-		val = mvreg_read(pp, MVNETA_GMAC_CLOCK_DIVIDER);
 | 
			
		||||
-		val &= ~MVNETA_GMAC_1MS_CLOCK_ENABLE;
 | 
			
		||||
-		mvreg_write(pp, MVNETA_GMAC_CLOCK_DIVIDER, val);
 | 
			
		||||
-
 | 
			
		||||
-		val = mvreg_read(pp, MVNETA_GMAC_CTRL_2);
 | 
			
		||||
-		val &= ~MVNETA_GMAC2_INBAND_AN_ENABLE;
 | 
			
		||||
-		mvreg_write(pp, MVNETA_GMAC_CTRL_2, val);
 | 
			
		||||
-	}
 | 
			
		||||
-
 | 
			
		||||
+	mvneta_set_autoneg(pp, pp->use_inband_status);
 | 
			
		||||
 	mvneta_set_ucast_table(pp, -1);
 | 
			
		||||
 	mvneta_set_special_mcast_table(pp, -1);
 | 
			
		||||
 	mvneta_set_other_mcast_table(pp, -1);
 | 
			
		||||
@@ -2956,10 +2962,43 @@ int mvneta_ethtool_get_settings(struct n
 | 
			
		||||
 int mvneta_ethtool_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 | 
			
		||||
 {
 | 
			
		||||
 	struct mvneta_port *pp = netdev_priv(dev);
 | 
			
		||||
+	struct phy_device *phydev = pp->phy_dev;
 | 
			
		||||
 
 | 
			
		||||
-	if (!pp->phy_dev)
 | 
			
		||||
+	if (!phydev)
 | 
			
		||||
 		return -ENODEV;
 | 
			
		||||
 
 | 
			
		||||
+	if ((cmd->autoneg == AUTONEG_ENABLE) != pp->use_inband_status) {
 | 
			
		||||
+		u32 val;
 | 
			
		||||
+
 | 
			
		||||
+		mvneta_set_autoneg(pp, cmd->autoneg == AUTONEG_ENABLE);
 | 
			
		||||
+
 | 
			
		||||
+		if (cmd->autoneg == AUTONEG_DISABLE) {
 | 
			
		||||
+			val = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG);
 | 
			
		||||
+			val &= ~(MVNETA_GMAC_CONFIG_MII_SPEED |
 | 
			
		||||
+				 MVNETA_GMAC_CONFIG_GMII_SPEED |
 | 
			
		||||
+				 MVNETA_GMAC_CONFIG_FULL_DUPLEX);
 | 
			
		||||
+
 | 
			
		||||
+			if (phydev->duplex)
 | 
			
		||||
+				val |= MVNETA_GMAC_CONFIG_FULL_DUPLEX;
 | 
			
		||||
+
 | 
			
		||||
+			if (phydev->speed == SPEED_1000)
 | 
			
		||||
+				val |= MVNETA_GMAC_CONFIG_GMII_SPEED;
 | 
			
		||||
+			else if (phydev->speed == SPEED_100)
 | 
			
		||||
+				val |= MVNETA_GMAC_CONFIG_MII_SPEED;
 | 
			
		||||
+
 | 
			
		||||
+			mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val);
 | 
			
		||||
+		}
 | 
			
		||||
+
 | 
			
		||||
+		pp->use_inband_status = (cmd->autoneg == AUTONEG_ENABLE);
 | 
			
		||||
+		netdev_info(pp->dev, "autoneg status set to %i\n",
 | 
			
		||||
+			    pp->use_inband_status);
 | 
			
		||||
+
 | 
			
		||||
+		if (netif_running(dev)) {
 | 
			
		||||
+			mvneta_port_down(pp);
 | 
			
		||||
+			mvneta_port_up(pp);
 | 
			
		||||
+		}
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
 	return phy_ethtool_sset(pp->phy_dev, cmd);
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,131 @@
 | 
			
		||||
From: Gregory CLEMENT <gregory.clement@free-electrons.com>
 | 
			
		||||
Date: Wed, 9 Dec 2015 18:23:48 +0100
 | 
			
		||||
Subject: [PATCH] net: mvneta: Make the default queue related for each port
 | 
			
		||||
 | 
			
		||||
Instead of using the same default queue for all the port. Move it in the
 | 
			
		||||
port struct. It will allow have a different default queue for each port.
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
 | 
			
		||||
Signed-off-by: David S. Miller <davem@davemloft.net>
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
+++ b/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
@@ -356,6 +356,7 @@ struct mvneta_port {
 | 
			
		||||
 	struct mvneta_tx_queue *txqs;
 | 
			
		||||
 	struct net_device *dev;
 | 
			
		||||
 	struct notifier_block cpu_notifier;
 | 
			
		||||
+	int rxq_def;
 | 
			
		||||
 
 | 
			
		||||
 	/* Core clock */
 | 
			
		||||
 	struct clk *clk;
 | 
			
		||||
@@ -819,7 +820,7 @@ static void mvneta_port_up(struct mvneta
 | 
			
		||||
 	mvreg_write(pp, MVNETA_TXQ_CMD, q_map);
 | 
			
		||||
 
 | 
			
		||||
 	/* Enable all initialized RXQs. */
 | 
			
		||||
-	mvreg_write(pp, MVNETA_RXQ_CMD, BIT(rxq_def));
 | 
			
		||||
+	mvreg_write(pp, MVNETA_RXQ_CMD, BIT(pp->rxq_def));
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
 /* Stop the Ethernet port activity */
 | 
			
		||||
@@ -1067,7 +1068,7 @@ static void mvneta_defaults_set(struct m
 | 
			
		||||
 	mvreg_write(pp, MVNETA_ACC_MODE, val);
 | 
			
		||||
 
 | 
			
		||||
 	/* Update val of portCfg register accordingly with all RxQueue types */
 | 
			
		||||
-	val = MVNETA_PORT_CONFIG_DEFL_VALUE(rxq_def);
 | 
			
		||||
+	val = MVNETA_PORT_CONFIG_DEFL_VALUE(pp->rxq_def);
 | 
			
		||||
 	mvreg_write(pp, MVNETA_PORT_CONFIG, val);
 | 
			
		||||
 
 | 
			
		||||
 	val = 0;
 | 
			
		||||
@@ -2101,19 +2102,19 @@ static void mvneta_set_rx_mode(struct ne
 | 
			
		||||
 	if (dev->flags & IFF_PROMISC) {
 | 
			
		||||
 		/* Accept all: Multicast + Unicast */
 | 
			
		||||
 		mvneta_rx_unicast_promisc_set(pp, 1);
 | 
			
		||||
-		mvneta_set_ucast_table(pp, rxq_def);
 | 
			
		||||
-		mvneta_set_special_mcast_table(pp, rxq_def);
 | 
			
		||||
-		mvneta_set_other_mcast_table(pp, rxq_def);
 | 
			
		||||
+		mvneta_set_ucast_table(pp, pp->rxq_def);
 | 
			
		||||
+		mvneta_set_special_mcast_table(pp, pp->rxq_def);
 | 
			
		||||
+		mvneta_set_other_mcast_table(pp, pp->rxq_def);
 | 
			
		||||
 	} else {
 | 
			
		||||
 		/* Accept single Unicast */
 | 
			
		||||
 		mvneta_rx_unicast_promisc_set(pp, 0);
 | 
			
		||||
 		mvneta_set_ucast_table(pp, -1);
 | 
			
		||||
-		mvneta_mac_addr_set(pp, dev->dev_addr, rxq_def);
 | 
			
		||||
+		mvneta_mac_addr_set(pp, dev->dev_addr, pp->rxq_def);
 | 
			
		||||
 
 | 
			
		||||
 		if (dev->flags & IFF_ALLMULTI) {
 | 
			
		||||
 			/* Accept all multicast */
 | 
			
		||||
-			mvneta_set_special_mcast_table(pp, rxq_def);
 | 
			
		||||
-			mvneta_set_other_mcast_table(pp, rxq_def);
 | 
			
		||||
+			mvneta_set_special_mcast_table(pp, pp->rxq_def);
 | 
			
		||||
+			mvneta_set_other_mcast_table(pp, pp->rxq_def);
 | 
			
		||||
 		} else {
 | 
			
		||||
 			/* Accept only initialized multicast */
 | 
			
		||||
 			mvneta_set_special_mcast_table(pp, -1);
 | 
			
		||||
@@ -2122,7 +2123,7 @@ static void mvneta_set_rx_mode(struct ne
 | 
			
		||||
 			if (!netdev_mc_empty(dev)) {
 | 
			
		||||
 				netdev_for_each_mc_addr(ha, dev) {
 | 
			
		||||
 					mvneta_mcast_addr_set(pp, ha->addr,
 | 
			
		||||
-							      rxq_def);
 | 
			
		||||
+							      pp->rxq_def);
 | 
			
		||||
 				}
 | 
			
		||||
 			}
 | 
			
		||||
 		}
 | 
			
		||||
@@ -2205,7 +2206,7 @@ static int mvneta_poll(struct napi_struc
 | 
			
		||||
 	 * RX packets
 | 
			
		||||
 	 */
 | 
			
		||||
 	cause_rx_tx |= port->cause_rx_tx;
 | 
			
		||||
-	rx_done = mvneta_rx(pp, budget, &pp->rxqs[rxq_def]);
 | 
			
		||||
+	rx_done = mvneta_rx(pp, budget, &pp->rxqs[pp->rxq_def]);
 | 
			
		||||
 	budget -= rx_done;
 | 
			
		||||
 
 | 
			
		||||
 	if (budget > 0) {
 | 
			
		||||
@@ -2418,17 +2419,17 @@ static void mvneta_cleanup_txqs(struct m
 | 
			
		||||
 /* Cleanup all Rx queues */
 | 
			
		||||
 static void mvneta_cleanup_rxqs(struct mvneta_port *pp)
 | 
			
		||||
 {
 | 
			
		||||
-	mvneta_rxq_deinit(pp, &pp->rxqs[rxq_def]);
 | 
			
		||||
+	mvneta_rxq_deinit(pp, &pp->rxqs[pp->rxq_def]);
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
 /* Init all Rx queues */
 | 
			
		||||
 static int mvneta_setup_rxqs(struct mvneta_port *pp)
 | 
			
		||||
 {
 | 
			
		||||
-	int err = mvneta_rxq_init(pp, &pp->rxqs[rxq_def]);
 | 
			
		||||
+	int err = mvneta_rxq_init(pp, &pp->rxqs[pp->rxq_def]);
 | 
			
		||||
 	if (err) {
 | 
			
		||||
 		netdev_err(pp->dev, "%s: can't create rxq=%d\n",
 | 
			
		||||
-			   __func__, rxq_def);
 | 
			
		||||
+			   __func__, pp->rxq_def);
 | 
			
		||||
 		mvneta_cleanup_rxqs(pp);
 | 
			
		||||
 		return err;
 | 
			
		||||
 	}
 | 
			
		||||
@@ -2634,7 +2635,7 @@ static int mvneta_set_mac_addr(struct ne
 | 
			
		||||
 	mvneta_mac_addr_set(pp, dev->dev_addr, -1);
 | 
			
		||||
 
 | 
			
		||||
 	/* Set new addr in hw */
 | 
			
		||||
-	mvneta_mac_addr_set(pp, sockaddr->sa_data, rxq_def);
 | 
			
		||||
+	mvneta_mac_addr_set(pp, sockaddr->sa_data, pp->rxq_def);
 | 
			
		||||
 
 | 
			
		||||
 	eth_commit_mac_addr_change(dev, addr);
 | 
			
		||||
 	return 0;
 | 
			
		||||
@@ -2753,7 +2754,7 @@ static void mvneta_percpu_elect(struct m
 | 
			
		||||
 {
 | 
			
		||||
 	int online_cpu_idx, cpu, i = 0;
 | 
			
		||||
 
 | 
			
		||||
-	online_cpu_idx = rxq_def % num_online_cpus();
 | 
			
		||||
+	online_cpu_idx = pp->rxq_def % num_online_cpus();
 | 
			
		||||
 
 | 
			
		||||
 	for_each_online_cpu(cpu) {
 | 
			
		||||
 		if (i == online_cpu_idx)
 | 
			
		||||
@@ -3363,6 +3364,8 @@ static int mvneta_probe(struct platform_
 | 
			
		||||
 				 strcmp(managed, "in-band-status") == 0);
 | 
			
		||||
 	pp->cpu_notifier.notifier_call = mvneta_percpu_notifier;
 | 
			
		||||
 
 | 
			
		||||
+	pp->rxq_def = rxq_def;
 | 
			
		||||
+
 | 
			
		||||
 	pp->clk = devm_clk_get(&pdev->dev, NULL);
 | 
			
		||||
 	if (IS_ERR(pp->clk)) {
 | 
			
		||||
 		err = PTR_ERR(pp->clk);
 | 
			
		||||
@@ -0,0 +1,278 @@
 | 
			
		||||
From: Gregory CLEMENT <gregory.clement@free-electrons.com>
 | 
			
		||||
Date: Wed, 9 Dec 2015 18:23:49 +0100
 | 
			
		||||
Subject: [PATCH] net: mvneta: Associate RX queues with each CPU
 | 
			
		||||
 | 
			
		||||
We enable the percpu interrupt for all the CPU and we just associate a
 | 
			
		||||
CPU to a few queue at the neta level. The mapping between the CPUs and
 | 
			
		||||
the queues is static. The queues are associated to the CPU module the
 | 
			
		||||
number of CPUs. However currently we only use on RX queue for a given
 | 
			
		||||
Ethernet port.
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
 | 
			
		||||
Signed-off-by: David S. Miller <davem@davemloft.net>
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
+++ b/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
@@ -110,9 +110,16 @@
 | 
			
		||||
 #define MVNETA_CPU_MAP(cpu)                      (0x2540 + ((cpu) << 2))
 | 
			
		||||
 #define      MVNETA_CPU_RXQ_ACCESS_ALL_MASK      0x000000ff
 | 
			
		||||
 #define      MVNETA_CPU_TXQ_ACCESS_ALL_MASK      0x0000ff00
 | 
			
		||||
+#define      MVNETA_CPU_RXQ_ACCESS(rxq)		 BIT(rxq)
 | 
			
		||||
 #define MVNETA_RXQ_TIME_COAL_REG(q)              (0x2580 + ((q) << 2))
 | 
			
		||||
 
 | 
			
		||||
-/* Exception Interrupt Port/Queue Cause register */
 | 
			
		||||
+/* Exception Interrupt Port/Queue Cause register
 | 
			
		||||
+ *
 | 
			
		||||
+ * Their behavior depend of the mapping done using the PCPX2Q
 | 
			
		||||
+ * registers. For a given CPU if the bit associated to a queue is not
 | 
			
		||||
+ * set, then for the register a read from this CPU will always return
 | 
			
		||||
+ * 0 and a write won't do anything
 | 
			
		||||
+ */
 | 
			
		||||
 
 | 
			
		||||
 #define MVNETA_INTR_NEW_CAUSE                    0x25a0
 | 
			
		||||
 #define MVNETA_INTR_NEW_MASK                     0x25a4
 | 
			
		||||
@@ -820,7 +827,13 @@ static void mvneta_port_up(struct mvneta
 | 
			
		||||
 	mvreg_write(pp, MVNETA_TXQ_CMD, q_map);
 | 
			
		||||
 
 | 
			
		||||
 	/* Enable all initialized RXQs. */
 | 
			
		||||
-	mvreg_write(pp, MVNETA_RXQ_CMD, BIT(pp->rxq_def));
 | 
			
		||||
+	for (queue = 0; queue < rxq_number; queue++) {
 | 
			
		||||
+		struct mvneta_rx_queue *rxq = &pp->rxqs[queue];
 | 
			
		||||
+
 | 
			
		||||
+		if (rxq->descs != NULL)
 | 
			
		||||
+			q_map |= (1 << queue);
 | 
			
		||||
+	}
 | 
			
		||||
+	mvreg_write(pp, MVNETA_RXQ_CMD, q_map);
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
 /* Stop the Ethernet port activity */
 | 
			
		||||
@@ -1026,6 +1039,7 @@ static void mvneta_defaults_set(struct m
 | 
			
		||||
 	int cpu;
 | 
			
		||||
 	int queue;
 | 
			
		||||
 	u32 val;
 | 
			
		||||
+	int max_cpu = num_present_cpus();
 | 
			
		||||
 
 | 
			
		||||
 	/* Clear all Cause registers */
 | 
			
		||||
 	mvreg_write(pp, MVNETA_INTR_NEW_CAUSE, 0);
 | 
			
		||||
@@ -1041,13 +1055,23 @@ static void mvneta_defaults_set(struct m
 | 
			
		||||
 	/* Enable MBUS Retry bit16 */
 | 
			
		||||
 	mvreg_write(pp, MVNETA_MBUS_RETRY, 0x20);
 | 
			
		||||
 
 | 
			
		||||
-	/* Set CPU queue access map - all CPUs have access to all RX
 | 
			
		||||
-	 * queues and to all TX queues
 | 
			
		||||
+	/* Set CPU queue access map. CPUs are assigned to the RX
 | 
			
		||||
+	 * queues modulo their number and all the TX queues are
 | 
			
		||||
+	 * assigned to the CPU associated to the default RX queue.
 | 
			
		||||
 	 */
 | 
			
		||||
-	for_each_present_cpu(cpu)
 | 
			
		||||
-		mvreg_write(pp, MVNETA_CPU_MAP(cpu),
 | 
			
		||||
-			    (MVNETA_CPU_RXQ_ACCESS_ALL_MASK |
 | 
			
		||||
-			     MVNETA_CPU_TXQ_ACCESS_ALL_MASK));
 | 
			
		||||
+	for_each_present_cpu(cpu) {
 | 
			
		||||
+		int rxq_map = 0, txq_map = 0;
 | 
			
		||||
+		int rxq;
 | 
			
		||||
+
 | 
			
		||||
+		for (rxq = 0; rxq < rxq_number; rxq++)
 | 
			
		||||
+			if ((rxq % max_cpu) == cpu)
 | 
			
		||||
+				rxq_map |= MVNETA_CPU_RXQ_ACCESS(rxq);
 | 
			
		||||
+
 | 
			
		||||
+		if (cpu == rxq_def)
 | 
			
		||||
+			txq_map = MVNETA_CPU_TXQ_ACCESS_ALL_MASK;
 | 
			
		||||
+
 | 
			
		||||
+		mvreg_write(pp, MVNETA_CPU_MAP(cpu), rxq_map | txq_map);
 | 
			
		||||
+	}
 | 
			
		||||
 
 | 
			
		||||
 	/* Reset RX and TX DMAs */
 | 
			
		||||
 	mvreg_write(pp, MVNETA_PORT_RX_RESET, MVNETA_PORT_RX_DMA_RESET);
 | 
			
		||||
@@ -2174,6 +2198,7 @@ static int mvneta_poll(struct napi_struc
 | 
			
		||||
 {
 | 
			
		||||
 	int rx_done = 0;
 | 
			
		||||
 	u32 cause_rx_tx;
 | 
			
		||||
+	int rx_queue;
 | 
			
		||||
 	struct mvneta_port *pp = netdev_priv(napi->dev);
 | 
			
		||||
 	struct mvneta_pcpu_port *port = this_cpu_ptr(pp->ports);
 | 
			
		||||
 
 | 
			
		||||
@@ -2205,8 +2230,15 @@ static int mvneta_poll(struct napi_struc
 | 
			
		||||
 	/* For the case where the last mvneta_poll did not process all
 | 
			
		||||
 	 * RX packets
 | 
			
		||||
 	 */
 | 
			
		||||
+	rx_queue = fls(((cause_rx_tx >> 8) & 0xff));
 | 
			
		||||
+
 | 
			
		||||
 	cause_rx_tx |= port->cause_rx_tx;
 | 
			
		||||
-	rx_done = mvneta_rx(pp, budget, &pp->rxqs[pp->rxq_def]);
 | 
			
		||||
+
 | 
			
		||||
+	if (rx_queue) {
 | 
			
		||||
+		rx_queue = rx_queue - 1;
 | 
			
		||||
+		rx_done = mvneta_rx(pp, budget, &pp->rxqs[rx_queue]);
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
 	budget -= rx_done;
 | 
			
		||||
 
 | 
			
		||||
 	if (budget > 0) {
 | 
			
		||||
@@ -2419,19 +2451,27 @@ static void mvneta_cleanup_txqs(struct m
 | 
			
		||||
 /* Cleanup all Rx queues */
 | 
			
		||||
 static void mvneta_cleanup_rxqs(struct mvneta_port *pp)
 | 
			
		||||
 {
 | 
			
		||||
-	mvneta_rxq_deinit(pp, &pp->rxqs[pp->rxq_def]);
 | 
			
		||||
+	int queue;
 | 
			
		||||
+
 | 
			
		||||
+	for (queue = 0; queue < txq_number; queue++)
 | 
			
		||||
+		mvneta_rxq_deinit(pp, &pp->rxqs[queue]);
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
 /* Init all Rx queues */
 | 
			
		||||
 static int mvneta_setup_rxqs(struct mvneta_port *pp)
 | 
			
		||||
 {
 | 
			
		||||
-	int err = mvneta_rxq_init(pp, &pp->rxqs[pp->rxq_def]);
 | 
			
		||||
-	if (err) {
 | 
			
		||||
-		netdev_err(pp->dev, "%s: can't create rxq=%d\n",
 | 
			
		||||
-			   __func__, pp->rxq_def);
 | 
			
		||||
-		mvneta_cleanup_rxqs(pp);
 | 
			
		||||
-		return err;
 | 
			
		||||
+	int queue;
 | 
			
		||||
+
 | 
			
		||||
+	for (queue = 0; queue < rxq_number; queue++) {
 | 
			
		||||
+		int err = mvneta_rxq_init(pp, &pp->rxqs[queue]);
 | 
			
		||||
+
 | 
			
		||||
+		if (err) {
 | 
			
		||||
+			netdev_err(pp->dev, "%s: can't create rxq=%d\n",
 | 
			
		||||
+				   __func__, queue);
 | 
			
		||||
+			mvneta_cleanup_rxqs(pp);
 | 
			
		||||
+			return err;
 | 
			
		||||
+		}
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
 	return 0;
 | 
			
		||||
@@ -2455,6 +2495,19 @@ static int mvneta_setup_txqs(struct mvne
 | 
			
		||||
 	return 0;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
+static void mvneta_percpu_unmask_interrupt(void *arg)
 | 
			
		||||
+{
 | 
			
		||||
+	struct mvneta_port *pp = arg;
 | 
			
		||||
+
 | 
			
		||||
+	/* All the queue are unmasked, but actually only the ones
 | 
			
		||||
+	 * maped to this CPU will be unmasked
 | 
			
		||||
+	 */
 | 
			
		||||
+	mvreg_write(pp, MVNETA_INTR_NEW_MASK,
 | 
			
		||||
+		    MVNETA_RX_INTR_MASK_ALL |
 | 
			
		||||
+		    MVNETA_TX_INTR_MASK_ALL |
 | 
			
		||||
+		    MVNETA_MISCINTR_INTR_MASK);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
 static void mvneta_start_dev(struct mvneta_port *pp)
 | 
			
		||||
 {
 | 
			
		||||
 	unsigned int cpu;
 | 
			
		||||
@@ -2472,11 +2525,10 @@ static void mvneta_start_dev(struct mvne
 | 
			
		||||
 		napi_enable(&port->napi);
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
-	/* Unmask interrupts */
 | 
			
		||||
-	mvreg_write(pp, MVNETA_INTR_NEW_MASK,
 | 
			
		||||
-		    MVNETA_RX_INTR_MASK(rxq_number) |
 | 
			
		||||
-		    MVNETA_TX_INTR_MASK(txq_number) |
 | 
			
		||||
-		    MVNETA_MISCINTR_INTR_MASK);
 | 
			
		||||
+	/* Unmask interrupts. It has to be done from each CPU */
 | 
			
		||||
+	for_each_online_cpu(cpu)
 | 
			
		||||
+		smp_call_function_single(cpu, mvneta_percpu_unmask_interrupt,
 | 
			
		||||
+					 pp, true);
 | 
			
		||||
 	mvreg_write(pp, MVNETA_INTR_MISC_MASK,
 | 
			
		||||
 		    MVNETA_CAUSE_PHY_STATUS_CHANGE |
 | 
			
		||||
 		    MVNETA_CAUSE_LINK_CHANGE |
 | 
			
		||||
@@ -2752,22 +2804,35 @@ static void mvneta_percpu_disable(void *
 | 
			
		||||
 
 | 
			
		||||
 static void mvneta_percpu_elect(struct mvneta_port *pp)
 | 
			
		||||
 {
 | 
			
		||||
-	int online_cpu_idx, cpu, i = 0;
 | 
			
		||||
+	int online_cpu_idx, max_cpu, cpu, i = 0;
 | 
			
		||||
 
 | 
			
		||||
 	online_cpu_idx = pp->rxq_def % num_online_cpus();
 | 
			
		||||
+	max_cpu = num_present_cpus();
 | 
			
		||||
 
 | 
			
		||||
 	for_each_online_cpu(cpu) {
 | 
			
		||||
-		if (i == online_cpu_idx)
 | 
			
		||||
-			/* Enable per-CPU interrupt on the one CPU we
 | 
			
		||||
-			 * just elected
 | 
			
		||||
+		int rxq_map = 0, txq_map = 0;
 | 
			
		||||
+		int rxq;
 | 
			
		||||
+
 | 
			
		||||
+		for (rxq = 0; rxq < rxq_number; rxq++)
 | 
			
		||||
+			if ((rxq % max_cpu) == cpu)
 | 
			
		||||
+				rxq_map |= MVNETA_CPU_RXQ_ACCESS(rxq);
 | 
			
		||||
+
 | 
			
		||||
+		if (i == online_cpu_idx) {
 | 
			
		||||
+			/* Map the default receive queue and transmit
 | 
			
		||||
+			 * queue to the elected CPU
 | 
			
		||||
 			 */
 | 
			
		||||
-			smp_call_function_single(cpu, mvneta_percpu_enable,
 | 
			
		||||
-						pp, true);
 | 
			
		||||
-		else
 | 
			
		||||
-			/* Disable per-CPU interrupt on all the other CPU */
 | 
			
		||||
-			smp_call_function_single(cpu, mvneta_percpu_disable,
 | 
			
		||||
-						pp, true);
 | 
			
		||||
+			rxq_map |= MVNETA_CPU_RXQ_ACCESS(pp->rxq_def);
 | 
			
		||||
+			txq_map = MVNETA_CPU_TXQ_ACCESS_ALL_MASK;
 | 
			
		||||
+		}
 | 
			
		||||
+		mvreg_write(pp, MVNETA_CPU_MAP(cpu), rxq_map | txq_map);
 | 
			
		||||
+
 | 
			
		||||
+		/* Update the interrupt mask on each CPU according the
 | 
			
		||||
+		 * new mapping
 | 
			
		||||
+		 */
 | 
			
		||||
+		smp_call_function_single(cpu, mvneta_percpu_unmask_interrupt,
 | 
			
		||||
+					 pp, true);
 | 
			
		||||
 		i++;
 | 
			
		||||
+
 | 
			
		||||
 	}
 | 
			
		||||
 };
 | 
			
		||||
 
 | 
			
		||||
@@ -2802,12 +2867,22 @@ static int mvneta_percpu_notifier(struct
 | 
			
		||||
 		mvreg_write(pp, MVNETA_INTR_MISC_MASK, 0);
 | 
			
		||||
 		napi_enable(&port->napi);
 | 
			
		||||
 
 | 
			
		||||
+
 | 
			
		||||
+		/* Enable per-CPU interrupts on the CPU that is
 | 
			
		||||
+		 * brought up.
 | 
			
		||||
+		 */
 | 
			
		||||
+		smp_call_function_single(cpu, mvneta_percpu_enable,
 | 
			
		||||
+					 pp, true);
 | 
			
		||||
+
 | 
			
		||||
 		/* Enable per-CPU interrupt on the one CPU we care
 | 
			
		||||
 		 * about.
 | 
			
		||||
 		 */
 | 
			
		||||
 		mvneta_percpu_elect(pp);
 | 
			
		||||
 
 | 
			
		||||
-		/* Unmask all ethernet port interrupts */
 | 
			
		||||
+		/* Unmask all ethernet port interrupts, as this
 | 
			
		||||
+		 * notifier is called for each CPU then the CPU to
 | 
			
		||||
+		 * Queue mapping is applied
 | 
			
		||||
+		 */
 | 
			
		||||
 		mvreg_write(pp, MVNETA_INTR_NEW_MASK,
 | 
			
		||||
 			MVNETA_RX_INTR_MASK(rxq_number) |
 | 
			
		||||
 			MVNETA_TX_INTR_MASK(txq_number) |
 | 
			
		||||
@@ -2858,7 +2933,7 @@ static int mvneta_percpu_notifier(struct
 | 
			
		||||
 static int mvneta_open(struct net_device *dev)
 | 
			
		||||
 {
 | 
			
		||||
 	struct mvneta_port *pp = netdev_priv(dev);
 | 
			
		||||
-	int ret;
 | 
			
		||||
+	int ret, cpu;
 | 
			
		||||
 
 | 
			
		||||
 	pp->pkt_size = MVNETA_RX_PKT_SIZE(pp->dev->mtu);
 | 
			
		||||
 	pp->frag_size = SKB_DATA_ALIGN(MVNETA_RX_BUF_SIZE(pp->pkt_size)) +
 | 
			
		||||
@@ -2888,8 +2963,13 @@ static int mvneta_open(struct net_device
 | 
			
		||||
 	 */
 | 
			
		||||
 	mvneta_percpu_disable(pp);
 | 
			
		||||
 
 | 
			
		||||
-	/* Elect a CPU to handle our RX queue interrupt */
 | 
			
		||||
-	mvneta_percpu_elect(pp);
 | 
			
		||||
+	/* Enable per-CPU interrupt on all the CPU to handle our RX
 | 
			
		||||
+	 * queue interrupts
 | 
			
		||||
+	 */
 | 
			
		||||
+	for_each_online_cpu(cpu)
 | 
			
		||||
+		smp_call_function_single(cpu, mvneta_percpu_enable,
 | 
			
		||||
+					 pp, true);
 | 
			
		||||
+
 | 
			
		||||
 
 | 
			
		||||
 	/* Register a CPU notifier to handle the case where our CPU
 | 
			
		||||
 	 * might be taken offline.
 | 
			
		||||
@@ -0,0 +1,191 @@
 | 
			
		||||
From: Gregory CLEMENT <gregory.clement@free-electrons.com>
 | 
			
		||||
Date: Wed, 9 Dec 2015 18:23:50 +0100
 | 
			
		||||
Subject: [PATCH] net: mvneta: Add naive RSS support
 | 
			
		||||
 | 
			
		||||
This patch adds the support for the RSS related ethtool
 | 
			
		||||
function. Currently it only uses one entry in the indirection table which
 | 
			
		||||
allows associating an mvneta interface to a given CPU.
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
 | 
			
		||||
Tested-by: Marcin Wojtas <mw@semihalf.com>
 | 
			
		||||
Signed-off-by: David S. Miller <davem@davemloft.net>
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
+++ b/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
@@ -261,6 +261,11 @@
 | 
			
		||||
 
 | 
			
		||||
 #define MVNETA_TX_MTU_MAX		0x3ffff
 | 
			
		||||
 
 | 
			
		||||
+/* The RSS lookup table actually has 256 entries but we do not use
 | 
			
		||||
+ * them yet
 | 
			
		||||
+ */
 | 
			
		||||
+#define MVNETA_RSS_LU_TABLE_SIZE	1
 | 
			
		||||
+
 | 
			
		||||
 /* TSO header size */
 | 
			
		||||
 #define TSO_HEADER_SIZE 128
 | 
			
		||||
 
 | 
			
		||||
@@ -382,6 +387,8 @@ struct mvneta_port {
 | 
			
		||||
 	unsigned int use_inband_status:1;
 | 
			
		||||
 
 | 
			
		||||
 	u64 ethtool_stats[ARRAY_SIZE(mvneta_statistics)];
 | 
			
		||||
+
 | 
			
		||||
+	u32 indir[MVNETA_RSS_LU_TABLE_SIZE];
 | 
			
		||||
 };
 | 
			
		||||
 
 | 
			
		||||
 /* The mvneta_tx_desc and mvneta_rx_desc structures describe the
 | 
			
		||||
@@ -1067,7 +1074,7 @@ static void mvneta_defaults_set(struct m
 | 
			
		||||
 			if ((rxq % max_cpu) == cpu)
 | 
			
		||||
 				rxq_map |= MVNETA_CPU_RXQ_ACCESS(rxq);
 | 
			
		||||
 
 | 
			
		||||
-		if (cpu == rxq_def)
 | 
			
		||||
+		if (cpu == pp->rxq_def)
 | 
			
		||||
 			txq_map = MVNETA_CPU_TXQ_ACCESS_ALL_MASK;
 | 
			
		||||
 
 | 
			
		||||
 		mvreg_write(pp, MVNETA_CPU_MAP(cpu), rxq_map | txq_map);
 | 
			
		||||
@@ -2508,6 +2515,18 @@ static void mvneta_percpu_unmask_interru
 | 
			
		||||
 		    MVNETA_MISCINTR_INTR_MASK);
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
+static void mvneta_percpu_mask_interrupt(void *arg)
 | 
			
		||||
+{
 | 
			
		||||
+	struct mvneta_port *pp = arg;
 | 
			
		||||
+
 | 
			
		||||
+	/* All the queue are masked, but actually only the ones
 | 
			
		||||
+	 * maped to this CPU will be masked
 | 
			
		||||
+	 */
 | 
			
		||||
+	mvreg_write(pp, MVNETA_INTR_NEW_MASK, 0);
 | 
			
		||||
+	mvreg_write(pp, MVNETA_INTR_OLD_MASK, 0);
 | 
			
		||||
+	mvreg_write(pp, MVNETA_INTR_MISC_MASK, 0);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
 static void mvneta_start_dev(struct mvneta_port *pp)
 | 
			
		||||
 {
 | 
			
		||||
 	unsigned int cpu;
 | 
			
		||||
@@ -3231,6 +3250,106 @@ static int mvneta_ethtool_get_sset_count
 | 
			
		||||
 	return -EOPNOTSUPP;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
+static u32 mvneta_ethtool_get_rxfh_indir_size(struct net_device *dev)
 | 
			
		||||
+{
 | 
			
		||||
+	return MVNETA_RSS_LU_TABLE_SIZE;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static int mvneta_ethtool_get_rxnfc(struct net_device *dev,
 | 
			
		||||
+				    struct ethtool_rxnfc *info,
 | 
			
		||||
+				    u32 *rules __always_unused)
 | 
			
		||||
+{
 | 
			
		||||
+	switch (info->cmd) {
 | 
			
		||||
+	case ETHTOOL_GRXRINGS:
 | 
			
		||||
+		info->data =  rxq_number;
 | 
			
		||||
+		return 0;
 | 
			
		||||
+	case ETHTOOL_GRXFH:
 | 
			
		||||
+		return -EOPNOTSUPP;
 | 
			
		||||
+	default:
 | 
			
		||||
+		return -EOPNOTSUPP;
 | 
			
		||||
+	}
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static int  mvneta_config_rss(struct mvneta_port *pp)
 | 
			
		||||
+{
 | 
			
		||||
+	int cpu;
 | 
			
		||||
+	u32 val;
 | 
			
		||||
+
 | 
			
		||||
+	netif_tx_stop_all_queues(pp->dev);
 | 
			
		||||
+
 | 
			
		||||
+	for_each_online_cpu(cpu)
 | 
			
		||||
+		smp_call_function_single(cpu, mvneta_percpu_mask_interrupt,
 | 
			
		||||
+					 pp, true);
 | 
			
		||||
+
 | 
			
		||||
+	/* We have to synchronise on the napi of each CPU */
 | 
			
		||||
+	for_each_online_cpu(cpu) {
 | 
			
		||||
+		struct mvneta_pcpu_port *pcpu_port =
 | 
			
		||||
+			per_cpu_ptr(pp->ports, cpu);
 | 
			
		||||
+
 | 
			
		||||
+		napi_synchronize(&pcpu_port->napi);
 | 
			
		||||
+		napi_disable(&pcpu_port->napi);
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	pp->rxq_def = pp->indir[0];
 | 
			
		||||
+
 | 
			
		||||
+	/* Update unicast mapping */
 | 
			
		||||
+	mvneta_set_rx_mode(pp->dev);
 | 
			
		||||
+
 | 
			
		||||
+	/* Update val of portCfg register accordingly with all RxQueue types */
 | 
			
		||||
+	val = MVNETA_PORT_CONFIG_DEFL_VALUE(pp->rxq_def);
 | 
			
		||||
+	mvreg_write(pp, MVNETA_PORT_CONFIG, val);
 | 
			
		||||
+
 | 
			
		||||
+	/* Update the elected CPU matching the new rxq_def */
 | 
			
		||||
+	mvneta_percpu_elect(pp);
 | 
			
		||||
+
 | 
			
		||||
+	/* We have to synchronise on the napi of each CPU */
 | 
			
		||||
+	for_each_online_cpu(cpu) {
 | 
			
		||||
+		struct mvneta_pcpu_port *pcpu_port =
 | 
			
		||||
+			per_cpu_ptr(pp->ports, cpu);
 | 
			
		||||
+
 | 
			
		||||
+		napi_enable(&pcpu_port->napi);
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	netif_tx_start_all_queues(pp->dev);
 | 
			
		||||
+
 | 
			
		||||
+	return 0;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static int mvneta_ethtool_set_rxfh(struct net_device *dev, const u32 *indir,
 | 
			
		||||
+				   const u8 *key, const u8 hfunc)
 | 
			
		||||
+{
 | 
			
		||||
+	struct mvneta_port *pp = netdev_priv(dev);
 | 
			
		||||
+	/* We require at least one supported parameter to be changed
 | 
			
		||||
+	 * and no change in any of the unsupported parameters
 | 
			
		||||
+	 */
 | 
			
		||||
+	if (key ||
 | 
			
		||||
+	    (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP))
 | 
			
		||||
+		return -EOPNOTSUPP;
 | 
			
		||||
+
 | 
			
		||||
+	if (!indir)
 | 
			
		||||
+		return 0;
 | 
			
		||||
+
 | 
			
		||||
+	memcpy(pp->indir, indir, MVNETA_RSS_LU_TABLE_SIZE);
 | 
			
		||||
+
 | 
			
		||||
+	return mvneta_config_rss(pp);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static int mvneta_ethtool_get_rxfh(struct net_device *dev, u32 *indir, u8 *key,
 | 
			
		||||
+				   u8 *hfunc)
 | 
			
		||||
+{
 | 
			
		||||
+	struct mvneta_port *pp = netdev_priv(dev);
 | 
			
		||||
+
 | 
			
		||||
+	if (hfunc)
 | 
			
		||||
+		*hfunc = ETH_RSS_HASH_TOP;
 | 
			
		||||
+
 | 
			
		||||
+	if (!indir)
 | 
			
		||||
+		return 0;
 | 
			
		||||
+
 | 
			
		||||
+	memcpy(indir, pp->indir, MVNETA_RSS_LU_TABLE_SIZE);
 | 
			
		||||
+
 | 
			
		||||
+	return 0;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
 static const struct net_device_ops mvneta_netdev_ops = {
 | 
			
		||||
 	.ndo_open            = mvneta_open,
 | 
			
		||||
 	.ndo_stop            = mvneta_stop,
 | 
			
		||||
@@ -3255,6 +3374,10 @@ const struct ethtool_ops mvneta_eth_tool
 | 
			
		||||
 	.get_strings	= mvneta_ethtool_get_strings,
 | 
			
		||||
 	.get_ethtool_stats = mvneta_ethtool_get_stats,
 | 
			
		||||
 	.get_sset_count	= mvneta_ethtool_get_sset_count,
 | 
			
		||||
+	.get_rxfh_indir_size = mvneta_ethtool_get_rxfh_indir_size,
 | 
			
		||||
+	.get_rxnfc	= mvneta_ethtool_get_rxnfc,
 | 
			
		||||
+	.get_rxfh	= mvneta_ethtool_get_rxfh,
 | 
			
		||||
+	.set_rxfh	= mvneta_ethtool_set_rxfh,
 | 
			
		||||
 };
 | 
			
		||||
 
 | 
			
		||||
 /* Initialize hw */
 | 
			
		||||
@@ -3446,6 +3569,8 @@ static int mvneta_probe(struct platform_
 | 
			
		||||
 
 | 
			
		||||
 	pp->rxq_def = rxq_def;
 | 
			
		||||
 
 | 
			
		||||
+	pp->indir[0] = rxq_def;
 | 
			
		||||
+
 | 
			
		||||
 	pp->clk = devm_clk_get(&pdev->dev, NULL);
 | 
			
		||||
 	if (IS_ERR(pp->clk)) {
 | 
			
		||||
 		err = PTR_ERR(pp->clk);
 | 
			
		||||
@@ -0,0 +1,124 @@
 | 
			
		||||
From: Gregory CLEMENT <gregory.clement@free-electrons.com>
 | 
			
		||||
Date: Wed, 9 Dec 2015 18:23:51 +0100
 | 
			
		||||
Subject: [PATCH] net: mvneta: Configure XPS support
 | 
			
		||||
 | 
			
		||||
With this patch each CPU is associated with its own set of TX queues.
 | 
			
		||||
 | 
			
		||||
It also setup the XPS with an initial configuration which set the
 | 
			
		||||
affinity matching the hardware configuration.
 | 
			
		||||
 | 
			
		||||
Suggested-by: Arnd Bergmann <arnd@arndb.de>
 | 
			
		||||
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
 | 
			
		||||
Signed-off-by: David S. Miller <davem@davemloft.net>
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
+++ b/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
@@ -111,6 +111,7 @@
 | 
			
		||||
 #define      MVNETA_CPU_RXQ_ACCESS_ALL_MASK      0x000000ff
 | 
			
		||||
 #define      MVNETA_CPU_TXQ_ACCESS_ALL_MASK      0x0000ff00
 | 
			
		||||
 #define      MVNETA_CPU_RXQ_ACCESS(rxq)		 BIT(rxq)
 | 
			
		||||
+#define      MVNETA_CPU_TXQ_ACCESS(txq)		 BIT(txq + 8)
 | 
			
		||||
 #define MVNETA_RXQ_TIME_COAL_REG(q)              (0x2580 + ((q) << 2))
 | 
			
		||||
 
 | 
			
		||||
 /* Exception Interrupt Port/Queue Cause register
 | 
			
		||||
@@ -514,6 +515,9 @@ struct mvneta_tx_queue {
 | 
			
		||||
 
 | 
			
		||||
 	/* DMA address of TSO headers */
 | 
			
		||||
 	dma_addr_t tso_hdrs_phys;
 | 
			
		||||
+
 | 
			
		||||
+	/* Affinity mask for CPUs*/
 | 
			
		||||
+	cpumask_t affinity_mask;
 | 
			
		||||
 };
 | 
			
		||||
 
 | 
			
		||||
 struct mvneta_rx_queue {
 | 
			
		||||
@@ -1062,20 +1066,30 @@ static void mvneta_defaults_set(struct m
 | 
			
		||||
 	/* Enable MBUS Retry bit16 */
 | 
			
		||||
 	mvreg_write(pp, MVNETA_MBUS_RETRY, 0x20);
 | 
			
		||||
 
 | 
			
		||||
-	/* Set CPU queue access map. CPUs are assigned to the RX
 | 
			
		||||
-	 * queues modulo their number and all the TX queues are
 | 
			
		||||
-	 * assigned to the CPU associated to the default RX queue.
 | 
			
		||||
+	/* Set CPU queue access map. CPUs are assigned to the RX and
 | 
			
		||||
+	 * TX queues modulo their number. If there is only one TX
 | 
			
		||||
+	 * queue then it is assigned to the CPU associated to the
 | 
			
		||||
+	 * default RX queue.
 | 
			
		||||
 	 */
 | 
			
		||||
 	for_each_present_cpu(cpu) {
 | 
			
		||||
 		int rxq_map = 0, txq_map = 0;
 | 
			
		||||
-		int rxq;
 | 
			
		||||
+		int rxq, txq;
 | 
			
		||||
 
 | 
			
		||||
 		for (rxq = 0; rxq < rxq_number; rxq++)
 | 
			
		||||
 			if ((rxq % max_cpu) == cpu)
 | 
			
		||||
 				rxq_map |= MVNETA_CPU_RXQ_ACCESS(rxq);
 | 
			
		||||
 
 | 
			
		||||
-		if (cpu == pp->rxq_def)
 | 
			
		||||
-			txq_map = MVNETA_CPU_TXQ_ACCESS_ALL_MASK;
 | 
			
		||||
+		for (txq = 0; txq < txq_number; txq++)
 | 
			
		||||
+			if ((txq % max_cpu) == cpu)
 | 
			
		||||
+				txq_map |= MVNETA_CPU_TXQ_ACCESS(txq);
 | 
			
		||||
+
 | 
			
		||||
+		/* With only one TX queue we configure a special case
 | 
			
		||||
+		 * which will allow to get all the irq on a single
 | 
			
		||||
+		 * CPU
 | 
			
		||||
+		 */
 | 
			
		||||
+		if (txq_number == 1)
 | 
			
		||||
+			txq_map = (cpu == pp->rxq_def) ?
 | 
			
		||||
+				MVNETA_CPU_TXQ_ACCESS(1) : 0;
 | 
			
		||||
 
 | 
			
		||||
 		mvreg_write(pp, MVNETA_CPU_MAP(cpu), rxq_map | txq_map);
 | 
			
		||||
 	}
 | 
			
		||||
@@ -2362,6 +2376,8 @@ static void mvneta_rxq_deinit(struct mvn
 | 
			
		||||
 static int mvneta_txq_init(struct mvneta_port *pp,
 | 
			
		||||
 			   struct mvneta_tx_queue *txq)
 | 
			
		||||
 {
 | 
			
		||||
+	int cpu;
 | 
			
		||||
+
 | 
			
		||||
 	txq->size = pp->tx_ring_size;
 | 
			
		||||
 
 | 
			
		||||
 	/* A queue must always have room for at least one skb.
 | 
			
		||||
@@ -2414,6 +2430,14 @@ static int mvneta_txq_init(struct mvneta
 | 
			
		||||
 	}
 | 
			
		||||
 	mvneta_tx_done_pkts_coal_set(pp, txq, txq->done_pkts_coal);
 | 
			
		||||
 
 | 
			
		||||
+	/* Setup XPS mapping */
 | 
			
		||||
+	if (txq_number > 1)
 | 
			
		||||
+		cpu = txq->id % num_present_cpus();
 | 
			
		||||
+	else
 | 
			
		||||
+		cpu = pp->rxq_def % num_present_cpus();
 | 
			
		||||
+	cpumask_set_cpu(cpu, &txq->affinity_mask);
 | 
			
		||||
+	netif_set_xps_queue(pp->dev, &txq->affinity_mask, txq->id);
 | 
			
		||||
+
 | 
			
		||||
 	return 0;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
@@ -2836,13 +2860,23 @@ static void mvneta_percpu_elect(struct m
 | 
			
		||||
 			if ((rxq % max_cpu) == cpu)
 | 
			
		||||
 				rxq_map |= MVNETA_CPU_RXQ_ACCESS(rxq);
 | 
			
		||||
 
 | 
			
		||||
-		if (i == online_cpu_idx) {
 | 
			
		||||
-			/* Map the default receive queue and transmit
 | 
			
		||||
-			 * queue to the elected CPU
 | 
			
		||||
+		if (i == online_cpu_idx)
 | 
			
		||||
+			/* Map the default receive queue queue to the
 | 
			
		||||
+			 * elected CPU
 | 
			
		||||
 			 */
 | 
			
		||||
 			rxq_map |= MVNETA_CPU_RXQ_ACCESS(pp->rxq_def);
 | 
			
		||||
-			txq_map = MVNETA_CPU_TXQ_ACCESS_ALL_MASK;
 | 
			
		||||
-		}
 | 
			
		||||
+
 | 
			
		||||
+		/* We update the TX queue map only if we have one
 | 
			
		||||
+		 * queue. In this case we associate the TX queue to
 | 
			
		||||
+		 * the CPU bound to the default RX queue
 | 
			
		||||
+		 */
 | 
			
		||||
+		if (txq_number == 1)
 | 
			
		||||
+			txq_map = (i == online_cpu_idx) ?
 | 
			
		||||
+				MVNETA_CPU_TXQ_ACCESS(1) : 0;
 | 
			
		||||
+		else
 | 
			
		||||
+			txq_map = mvreg_read(pp, MVNETA_CPU_MAP(cpu)) &
 | 
			
		||||
+				MVNETA_CPU_TXQ_ACCESS_ALL_MASK;
 | 
			
		||||
+
 | 
			
		||||
 		mvreg_write(pp, MVNETA_CPU_MAP(cpu), rxq_map | txq_map);
 | 
			
		||||
 
 | 
			
		||||
 		/* Update the interrupt mask on each CPU according the
 | 
			
		||||
@@ -0,0 +1,46 @@
 | 
			
		||||
From: Jisheng Zhang <jszhang@marvell.com>
 | 
			
		||||
Date: Wed, 20 Jan 2016 16:36:25 +0800
 | 
			
		||||
Subject: [PATCH] net: mvneta: fix trivial cut-off issue in
 | 
			
		||||
 mvneta_ethtool_update_stats
 | 
			
		||||
 | 
			
		||||
When s->type is T_REG_64, the high 32bits are lost in val. This patch
 | 
			
		||||
fixes this trivial issue.
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Jisheng Zhang <jszhang@marvell.com>
 | 
			
		||||
Fixes: 9b0cdefa4cd5 ("net: mvneta: add ethtool statistics")
 | 
			
		||||
Signed-off-by: David S. Miller <davem@davemloft.net>
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
+++ b/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
@@ -3242,26 +3242,25 @@ static void mvneta_ethtool_update_stats(
 | 
			
		||||
 	const struct mvneta_statistic *s;
 | 
			
		||||
 	void __iomem *base = pp->base;
 | 
			
		||||
 	u32 high, low, val;
 | 
			
		||||
+	u64 val64;
 | 
			
		||||
 	int i;
 | 
			
		||||
 
 | 
			
		||||
 	for (i = 0, s = mvneta_statistics;
 | 
			
		||||
 	     s < mvneta_statistics + ARRAY_SIZE(mvneta_statistics);
 | 
			
		||||
 	     s++, i++) {
 | 
			
		||||
-		val = 0;
 | 
			
		||||
-
 | 
			
		||||
 		switch (s->type) {
 | 
			
		||||
 		case T_REG_32:
 | 
			
		||||
 			val = readl_relaxed(base + s->offset);
 | 
			
		||||
+			pp->ethtool_stats[i] += val;
 | 
			
		||||
 			break;
 | 
			
		||||
 		case T_REG_64:
 | 
			
		||||
 			/* Docs say to read low 32-bit then high */
 | 
			
		||||
 			low = readl_relaxed(base + s->offset);
 | 
			
		||||
 			high = readl_relaxed(base + s->offset + 4);
 | 
			
		||||
-			val = (u64)high << 32 | low;
 | 
			
		||||
+			val64 = (u64)high << 32 | low;
 | 
			
		||||
+			pp->ethtool_stats[i] += val64;
 | 
			
		||||
 			break;
 | 
			
		||||
 		}
 | 
			
		||||
-
 | 
			
		||||
-		pp->ethtool_stats[i] += val;
 | 
			
		||||
 	}
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,55 @@
 | 
			
		||||
From: Gregory CLEMENT <gregory.clement@free-electrons.com>
 | 
			
		||||
Date: Thu, 4 Feb 2016 22:09:23 +0100
 | 
			
		||||
Subject: [PATCH] net: mvneta: Fix for_each_present_cpu usage
 | 
			
		||||
 | 
			
		||||
This patch convert the for_each_present in on_each_cpu, instead of
 | 
			
		||||
applying on the present cpus it will be applied only on the online cpus.
 | 
			
		||||
This fix a bug reported on
 | 
			
		||||
http://thread.gmane.org/gmane.linux.ports.arm.kernel/468173.
 | 
			
		||||
 | 
			
		||||
Using the macro on_each_cpu (instead of a for_each_* loop) also ensures
 | 
			
		||||
that all the calls will be done all at once.
 | 
			
		||||
 | 
			
		||||
Fixes: f86428854480 ("net: mvneta: Statically assign queues to CPUs")
 | 
			
		||||
Reported-by: Stefan Roese <stefan.roese@gmail.com>
 | 
			
		||||
Suggested-by: Jisheng Zhang <jszhang@marvell.com>
 | 
			
		||||
Suggested-by: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
 | 
			
		||||
Signed-off-by: David S. Miller <davem@davemloft.net>
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
+++ b/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
@@ -2562,7 +2562,7 @@ static void mvneta_start_dev(struct mvne
 | 
			
		||||
 	mvneta_port_enable(pp);
 | 
			
		||||
 
 | 
			
		||||
 	/* Enable polling on the port */
 | 
			
		||||
-	for_each_present_cpu(cpu) {
 | 
			
		||||
+	for_each_online_cpu(cpu) {
 | 
			
		||||
 		struct mvneta_pcpu_port *port = per_cpu_ptr(pp->ports, cpu);
 | 
			
		||||
 
 | 
			
		||||
 		napi_enable(&port->napi);
 | 
			
		||||
@@ -2587,7 +2587,7 @@ static void mvneta_stop_dev(struct mvnet
 | 
			
		||||
 
 | 
			
		||||
 	phy_stop(pp->phy_dev);
 | 
			
		||||
 
 | 
			
		||||
-	for_each_present_cpu(cpu) {
 | 
			
		||||
+	for_each_online_cpu(cpu) {
 | 
			
		||||
 		struct mvneta_pcpu_port *port = per_cpu_ptr(pp->ports, cpu);
 | 
			
		||||
 
 | 
			
		||||
 		napi_disable(&port->napi);
 | 
			
		||||
@@ -3055,13 +3055,11 @@ err_cleanup_rxqs:
 | 
			
		||||
 static int mvneta_stop(struct net_device *dev)
 | 
			
		||||
 {
 | 
			
		||||
 	struct mvneta_port *pp = netdev_priv(dev);
 | 
			
		||||
-	int cpu;
 | 
			
		||||
 
 | 
			
		||||
 	mvneta_stop_dev(pp);
 | 
			
		||||
 	mvneta_mdio_remove(pp);
 | 
			
		||||
 	unregister_cpu_notifier(&pp->cpu_notifier);
 | 
			
		||||
-	for_each_present_cpu(cpu)
 | 
			
		||||
-		smp_call_function_single(cpu, mvneta_percpu_disable, pp, true);
 | 
			
		||||
+	on_each_cpu(mvneta_percpu_disable, pp, true);
 | 
			
		||||
 	free_percpu_irq(dev->irq, pp->ports);
 | 
			
		||||
 	mvneta_cleanup_rxqs(pp);
 | 
			
		||||
 	mvneta_cleanup_txqs(pp);
 | 
			
		||||
@@ -0,0 +1,57 @@
 | 
			
		||||
From: Gregory CLEMENT <gregory.clement@free-electrons.com>
 | 
			
		||||
Date: Thu, 4 Feb 2016 22:09:24 +0100
 | 
			
		||||
Subject: [PATCH] net: mvneta: Fix the CPU choice in mvneta_percpu_elect
 | 
			
		||||
 | 
			
		||||
When passing to the management of multiple RX queue, the
 | 
			
		||||
mvneta_percpu_elect function was broken. The use of the modulo can lead
 | 
			
		||||
to elect the wrong cpu. For example with rxq_def=2, if the CPU 2 goes
 | 
			
		||||
offline and then online, we ended with the third RX queue activated in
 | 
			
		||||
the same time on CPU 0 and CPU2, which lead to a kernel crash.
 | 
			
		||||
 | 
			
		||||
With this fix, we don't try to get "the closer" CPU if the default CPU is
 | 
			
		||||
gone, now we just use CPU 0 which always be there. Thanks to this, the
 | 
			
		||||
code becomes more readable, easier to maintain and more predicable.
 | 
			
		||||
 | 
			
		||||
Cc: stable@vger.kernel.org
 | 
			
		||||
Fixes: 2dcf75e2793c ("net: mvneta: Associate RX queues with each CPU")
 | 
			
		||||
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
 | 
			
		||||
Signed-off-by: David S. Miller <davem@davemloft.net>
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
+++ b/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
@@ -2847,9 +2847,14 @@ static void mvneta_percpu_disable(void *
 | 
			
		||||
 
 | 
			
		||||
 static void mvneta_percpu_elect(struct mvneta_port *pp)
 | 
			
		||||
 {
 | 
			
		||||
-	int online_cpu_idx, max_cpu, cpu, i = 0;
 | 
			
		||||
+	int elected_cpu = 0, max_cpu, cpu, i = 0;
 | 
			
		||||
+
 | 
			
		||||
+	/* Use the cpu associated to the rxq when it is online, in all
 | 
			
		||||
+	 * the other cases, use the cpu 0 which can't be offline.
 | 
			
		||||
+	 */
 | 
			
		||||
+	if (cpu_online(pp->rxq_def))
 | 
			
		||||
+		elected_cpu = pp->rxq_def;
 | 
			
		||||
 
 | 
			
		||||
-	online_cpu_idx = pp->rxq_def % num_online_cpus();
 | 
			
		||||
 	max_cpu = num_present_cpus();
 | 
			
		||||
 
 | 
			
		||||
 	for_each_online_cpu(cpu) {
 | 
			
		||||
@@ -2860,7 +2865,7 @@ static void mvneta_percpu_elect(struct m
 | 
			
		||||
 			if ((rxq % max_cpu) == cpu)
 | 
			
		||||
 				rxq_map |= MVNETA_CPU_RXQ_ACCESS(rxq);
 | 
			
		||||
 
 | 
			
		||||
-		if (i == online_cpu_idx)
 | 
			
		||||
+		if (cpu == elected_cpu)
 | 
			
		||||
 			/* Map the default receive queue queue to the
 | 
			
		||||
 			 * elected CPU
 | 
			
		||||
 			 */
 | 
			
		||||
@@ -2871,7 +2876,7 @@ static void mvneta_percpu_elect(struct m
 | 
			
		||||
 		 * the CPU bound to the default RX queue
 | 
			
		||||
 		 */
 | 
			
		||||
 		if (txq_number == 1)
 | 
			
		||||
-			txq_map = (i == online_cpu_idx) ?
 | 
			
		||||
+			txq_map = (cpu == elected_cpu) ?
 | 
			
		||||
 				MVNETA_CPU_TXQ_ACCESS(1) : 0;
 | 
			
		||||
 		else
 | 
			
		||||
 			txq_map = mvreg_read(pp, MVNETA_CPU_MAP(cpu)) &
 | 
			
		||||
@@ -0,0 +1,68 @@
 | 
			
		||||
From: Gregory CLEMENT <gregory.clement@free-electrons.com>
 | 
			
		||||
Date: Thu, 4 Feb 2016 22:09:25 +0100
 | 
			
		||||
Subject: [PATCH] net: mvneta: Use on_each_cpu when possible
 | 
			
		||||
 | 
			
		||||
Instead of using a for_each_* loop in which we just call the
 | 
			
		||||
smp_call_function_single macro, it is more simple to directly use the
 | 
			
		||||
on_each_cpu macro. Moreover, this macro ensures that the calls will be
 | 
			
		||||
done all at once.
 | 
			
		||||
 | 
			
		||||
Suggested-by: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
 | 
			
		||||
Signed-off-by: David S. Miller <davem@davemloft.net>
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
+++ b/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
@@ -2553,7 +2553,7 @@ static void mvneta_percpu_mask_interrupt
 | 
			
		||||
 
 | 
			
		||||
 static void mvneta_start_dev(struct mvneta_port *pp)
 | 
			
		||||
 {
 | 
			
		||||
-	unsigned int cpu;
 | 
			
		||||
+	int cpu;
 | 
			
		||||
 
 | 
			
		||||
 	mvneta_max_rx_size_set(pp, pp->pkt_size);
 | 
			
		||||
 	mvneta_txq_max_tx_size_set(pp, pp->pkt_size);
 | 
			
		||||
@@ -2569,9 +2569,8 @@ static void mvneta_start_dev(struct mvne
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
 	/* Unmask interrupts. It has to be done from each CPU */
 | 
			
		||||
-	for_each_online_cpu(cpu)
 | 
			
		||||
-		smp_call_function_single(cpu, mvneta_percpu_unmask_interrupt,
 | 
			
		||||
-					 pp, true);
 | 
			
		||||
+	on_each_cpu(mvneta_percpu_unmask_interrupt, pp, true);
 | 
			
		||||
+
 | 
			
		||||
 	mvreg_write(pp, MVNETA_INTR_MISC_MASK,
 | 
			
		||||
 		    MVNETA_CAUSE_PHY_STATUS_CHANGE |
 | 
			
		||||
 		    MVNETA_CAUSE_LINK_CHANGE |
 | 
			
		||||
@@ -2991,7 +2990,7 @@ static int mvneta_percpu_notifier(struct
 | 
			
		||||
 static int mvneta_open(struct net_device *dev)
 | 
			
		||||
 {
 | 
			
		||||
 	struct mvneta_port *pp = netdev_priv(dev);
 | 
			
		||||
-	int ret, cpu;
 | 
			
		||||
+	int ret;
 | 
			
		||||
 
 | 
			
		||||
 	pp->pkt_size = MVNETA_RX_PKT_SIZE(pp->dev->mtu);
 | 
			
		||||
 	pp->frag_size = SKB_DATA_ALIGN(MVNETA_RX_BUF_SIZE(pp->pkt_size)) +
 | 
			
		||||
@@ -3024,9 +3023,7 @@ static int mvneta_open(struct net_device
 | 
			
		||||
 	/* Enable per-CPU interrupt on all the CPU to handle our RX
 | 
			
		||||
 	 * queue interrupts
 | 
			
		||||
 	 */
 | 
			
		||||
-	for_each_online_cpu(cpu)
 | 
			
		||||
-		smp_call_function_single(cpu, mvneta_percpu_enable,
 | 
			
		||||
-					 pp, true);
 | 
			
		||||
+	on_each_cpu(mvneta_percpu_enable, pp, true);
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
 	/* Register a CPU notifier to handle the case where our CPU
 | 
			
		||||
@@ -3313,9 +3310,7 @@ static int  mvneta_config_rss(struct mvn
 | 
			
		||||
 
 | 
			
		||||
 	netif_tx_stop_all_queues(pp->dev);
 | 
			
		||||
 
 | 
			
		||||
-	for_each_online_cpu(cpu)
 | 
			
		||||
-		smp_call_function_single(cpu, mvneta_percpu_mask_interrupt,
 | 
			
		||||
-					 pp, true);
 | 
			
		||||
+	on_each_cpu(mvneta_percpu_mask_interrupt, pp, true);
 | 
			
		||||
 
 | 
			
		||||
 	/* We have to synchronise on the napi of each CPU */
 | 
			
		||||
 	for_each_online_cpu(cpu) {
 | 
			
		||||
@@ -0,0 +1,179 @@
 | 
			
		||||
From: Gregory CLEMENT <gregory.clement@free-electrons.com>
 | 
			
		||||
Date: Thu, 4 Feb 2016 22:09:27 +0100
 | 
			
		||||
Subject: [PATCH] net: mvneta: Modify the queue related fields from each cpu
 | 
			
		||||
 | 
			
		||||
In the MVNETA_INTR_* registers, the queues related fields are per cpu,
 | 
			
		||||
according to the datasheet (comment in [] are added by me):
 | 
			
		||||
"In a multi-CPU system, bits of RX[or TX] queues for which the access by
 | 
			
		||||
the reading[or writing] CPU is disabled are read as 0, and cannot be
 | 
			
		||||
cleared[or written]."
 | 
			
		||||
 | 
			
		||||
That means that each time we want to manipulate these bits we had to do
 | 
			
		||||
it on each cpu and not only on the current cpu.
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
 | 
			
		||||
Signed-off-by: David S. Miller <davem@davemloft.net>
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
+++ b/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
@@ -1036,6 +1036,43 @@ static void mvneta_set_autoneg(struct mv
 | 
			
		||||
 	}
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
+static void mvneta_percpu_unmask_interrupt(void *arg)
 | 
			
		||||
+{
 | 
			
		||||
+	struct mvneta_port *pp = arg;
 | 
			
		||||
+
 | 
			
		||||
+	/* All the queue are unmasked, but actually only the ones
 | 
			
		||||
+	 * mapped to this CPU will be unmasked
 | 
			
		||||
+	 */
 | 
			
		||||
+	mvreg_write(pp, MVNETA_INTR_NEW_MASK,
 | 
			
		||||
+		    MVNETA_RX_INTR_MASK_ALL |
 | 
			
		||||
+		    MVNETA_TX_INTR_MASK_ALL |
 | 
			
		||||
+		    MVNETA_MISCINTR_INTR_MASK);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static void mvneta_percpu_mask_interrupt(void *arg)
 | 
			
		||||
+{
 | 
			
		||||
+	struct mvneta_port *pp = arg;
 | 
			
		||||
+
 | 
			
		||||
+	/* All the queue are masked, but actually only the ones
 | 
			
		||||
+	 * mapped to this CPU will be masked
 | 
			
		||||
+	 */
 | 
			
		||||
+	mvreg_write(pp, MVNETA_INTR_NEW_MASK, 0);
 | 
			
		||||
+	mvreg_write(pp, MVNETA_INTR_OLD_MASK, 0);
 | 
			
		||||
+	mvreg_write(pp, MVNETA_INTR_MISC_MASK, 0);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static void mvneta_percpu_clear_intr_cause(void *arg)
 | 
			
		||||
+{
 | 
			
		||||
+	struct mvneta_port *pp = arg;
 | 
			
		||||
+
 | 
			
		||||
+	/* All the queue are cleared, but actually only the ones
 | 
			
		||||
+	 * mapped to this CPU will be cleared
 | 
			
		||||
+	 */
 | 
			
		||||
+	mvreg_write(pp, MVNETA_INTR_NEW_CAUSE, 0);
 | 
			
		||||
+	mvreg_write(pp, MVNETA_INTR_MISC_CAUSE, 0);
 | 
			
		||||
+	mvreg_write(pp, MVNETA_INTR_OLD_CAUSE, 0);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
 /* This method sets defaults to the NETA port:
 | 
			
		||||
  *	Clears interrupt Cause and Mask registers.
 | 
			
		||||
  *	Clears all MAC tables.
 | 
			
		||||
@@ -1053,14 +1090,10 @@ static void mvneta_defaults_set(struct m
 | 
			
		||||
 	int max_cpu = num_present_cpus();
 | 
			
		||||
 
 | 
			
		||||
 	/* Clear all Cause registers */
 | 
			
		||||
-	mvreg_write(pp, MVNETA_INTR_NEW_CAUSE, 0);
 | 
			
		||||
-	mvreg_write(pp, MVNETA_INTR_OLD_CAUSE, 0);
 | 
			
		||||
-	mvreg_write(pp, MVNETA_INTR_MISC_CAUSE, 0);
 | 
			
		||||
+	on_each_cpu(mvneta_percpu_clear_intr_cause, pp, true);
 | 
			
		||||
 
 | 
			
		||||
 	/* Mask all interrupts */
 | 
			
		||||
-	mvreg_write(pp, MVNETA_INTR_NEW_MASK, 0);
 | 
			
		||||
-	mvreg_write(pp, MVNETA_INTR_OLD_MASK, 0);
 | 
			
		||||
-	mvreg_write(pp, MVNETA_INTR_MISC_MASK, 0);
 | 
			
		||||
+	on_each_cpu(mvneta_percpu_mask_interrupt, pp, true);
 | 
			
		||||
 	mvreg_write(pp, MVNETA_INTR_ENABLE, 0);
 | 
			
		||||
 
 | 
			
		||||
 	/* Enable MBUS Retry bit16 */
 | 
			
		||||
@@ -2526,31 +2559,6 @@ static int mvneta_setup_txqs(struct mvne
 | 
			
		||||
 	return 0;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
-static void mvneta_percpu_unmask_interrupt(void *arg)
 | 
			
		||||
-{
 | 
			
		||||
-	struct mvneta_port *pp = arg;
 | 
			
		||||
-
 | 
			
		||||
-	/* All the queue are unmasked, but actually only the ones
 | 
			
		||||
-	 * maped to this CPU will be unmasked
 | 
			
		||||
-	 */
 | 
			
		||||
-	mvreg_write(pp, MVNETA_INTR_NEW_MASK,
 | 
			
		||||
-		    MVNETA_RX_INTR_MASK_ALL |
 | 
			
		||||
-		    MVNETA_TX_INTR_MASK_ALL |
 | 
			
		||||
-		    MVNETA_MISCINTR_INTR_MASK);
 | 
			
		||||
-}
 | 
			
		||||
-
 | 
			
		||||
-static void mvneta_percpu_mask_interrupt(void *arg)
 | 
			
		||||
-{
 | 
			
		||||
-	struct mvneta_port *pp = arg;
 | 
			
		||||
-
 | 
			
		||||
-	/* All the queue are masked, but actually only the ones
 | 
			
		||||
-	 * maped to this CPU will be masked
 | 
			
		||||
-	 */
 | 
			
		||||
-	mvreg_write(pp, MVNETA_INTR_NEW_MASK, 0);
 | 
			
		||||
-	mvreg_write(pp, MVNETA_INTR_OLD_MASK, 0);
 | 
			
		||||
-	mvreg_write(pp, MVNETA_INTR_MISC_MASK, 0);
 | 
			
		||||
-}
 | 
			
		||||
-
 | 
			
		||||
 static void mvneta_start_dev(struct mvneta_port *pp)
 | 
			
		||||
 {
 | 
			
		||||
 	int cpu;
 | 
			
		||||
@@ -2601,13 +2609,10 @@ static void mvneta_stop_dev(struct mvnet
 | 
			
		||||
 	mvneta_port_disable(pp);
 | 
			
		||||
 
 | 
			
		||||
 	/* Clear all ethernet port interrupts */
 | 
			
		||||
-	mvreg_write(pp, MVNETA_INTR_MISC_CAUSE, 0);
 | 
			
		||||
-	mvreg_write(pp, MVNETA_INTR_OLD_CAUSE, 0);
 | 
			
		||||
+	on_each_cpu(mvneta_percpu_clear_intr_cause, pp, true);
 | 
			
		||||
 
 | 
			
		||||
 	/* Mask all ethernet port interrupts */
 | 
			
		||||
-	mvreg_write(pp, MVNETA_INTR_NEW_MASK, 0);
 | 
			
		||||
-	mvreg_write(pp, MVNETA_INTR_OLD_MASK, 0);
 | 
			
		||||
-	mvreg_write(pp, MVNETA_INTR_MISC_MASK, 0);
 | 
			
		||||
+	on_each_cpu(mvneta_percpu_mask_interrupt, pp, true);
 | 
			
		||||
 
 | 
			
		||||
 	mvneta_tx_reset(pp);
 | 
			
		||||
 	mvneta_rx_reset(pp);
 | 
			
		||||
@@ -2919,9 +2924,7 @@ static int mvneta_percpu_notifier(struct
 | 
			
		||||
 		}
 | 
			
		||||
 
 | 
			
		||||
 		/* Mask all ethernet port interrupts */
 | 
			
		||||
-		mvreg_write(pp, MVNETA_INTR_NEW_MASK, 0);
 | 
			
		||||
-		mvreg_write(pp, MVNETA_INTR_OLD_MASK, 0);
 | 
			
		||||
-		mvreg_write(pp, MVNETA_INTR_MISC_MASK, 0);
 | 
			
		||||
+		on_each_cpu(mvneta_percpu_mask_interrupt, pp, true);
 | 
			
		||||
 		napi_enable(&port->napi);
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
@@ -2936,14 +2939,8 @@ static int mvneta_percpu_notifier(struct
 | 
			
		||||
 		 */
 | 
			
		||||
 		mvneta_percpu_elect(pp);
 | 
			
		||||
 
 | 
			
		||||
-		/* Unmask all ethernet port interrupts, as this
 | 
			
		||||
-		 * notifier is called for each CPU then the CPU to
 | 
			
		||||
-		 * Queue mapping is applied
 | 
			
		||||
-		 */
 | 
			
		||||
-		mvreg_write(pp, MVNETA_INTR_NEW_MASK,
 | 
			
		||||
-			MVNETA_RX_INTR_MASK(rxq_number) |
 | 
			
		||||
-			MVNETA_TX_INTR_MASK(txq_number) |
 | 
			
		||||
-			MVNETA_MISCINTR_INTR_MASK);
 | 
			
		||||
+		/* Unmask all ethernet port interrupts */
 | 
			
		||||
+		on_each_cpu(mvneta_percpu_unmask_interrupt, pp, true);
 | 
			
		||||
 		mvreg_write(pp, MVNETA_INTR_MISC_MASK,
 | 
			
		||||
 			MVNETA_CAUSE_PHY_STATUS_CHANGE |
 | 
			
		||||
 			MVNETA_CAUSE_LINK_CHANGE |
 | 
			
		||||
@@ -2954,9 +2951,7 @@ static int mvneta_percpu_notifier(struct
 | 
			
		||||
 	case CPU_DOWN_PREPARE_FROZEN:
 | 
			
		||||
 		netif_tx_stop_all_queues(pp->dev);
 | 
			
		||||
 		/* Mask all ethernet port interrupts */
 | 
			
		||||
-		mvreg_write(pp, MVNETA_INTR_NEW_MASK, 0);
 | 
			
		||||
-		mvreg_write(pp, MVNETA_INTR_OLD_MASK, 0);
 | 
			
		||||
-		mvreg_write(pp, MVNETA_INTR_MISC_MASK, 0);
 | 
			
		||||
+		on_each_cpu(mvneta_percpu_mask_interrupt, pp, true);
 | 
			
		||||
 
 | 
			
		||||
 		napi_synchronize(&port->napi);
 | 
			
		||||
 		napi_disable(&port->napi);
 | 
			
		||||
@@ -2972,10 +2967,7 @@ static int mvneta_percpu_notifier(struct
 | 
			
		||||
 		/* Check if a new CPU must be elected now this on is down */
 | 
			
		||||
 		mvneta_percpu_elect(pp);
 | 
			
		||||
 		/* Unmask all ethernet port interrupts */
 | 
			
		||||
-		mvreg_write(pp, MVNETA_INTR_NEW_MASK,
 | 
			
		||||
-			MVNETA_RX_INTR_MASK(rxq_number) |
 | 
			
		||||
-			MVNETA_TX_INTR_MASK(txq_number) |
 | 
			
		||||
-			MVNETA_MISCINTR_INTR_MASK);
 | 
			
		||||
+		on_each_cpu(mvneta_percpu_unmask_interrupt, pp, true);
 | 
			
		||||
 		mvreg_write(pp, MVNETA_INTR_MISC_MASK,
 | 
			
		||||
 			MVNETA_CAUSE_PHY_STATUS_CHANGE |
 | 
			
		||||
 			MVNETA_CAUSE_LINK_CHANGE |
 | 
			
		||||
@@ -0,0 +1,68 @@
 | 
			
		||||
From: Gregory CLEMENT <gregory.clement@free-electrons.com>
 | 
			
		||||
Date: Thu, 4 Feb 2016 22:09:28 +0100
 | 
			
		||||
Subject: [PATCH] net: mvneta: The mvneta_percpu_elect function should be
 | 
			
		||||
 atomic
 | 
			
		||||
 | 
			
		||||
Electing a CPU must be done in an atomic way: it should be done after or
 | 
			
		||||
before the removal/insertion of a CPU and this function is not reentrant.
 | 
			
		||||
 | 
			
		||||
During the loop of mvneta_percpu_elect we associates the queues to the
 | 
			
		||||
CPUs, if there is a topology change during this loop, then the mapping
 | 
			
		||||
between the CPUs and the queues could be wrong. During this loop the
 | 
			
		||||
interrupt mask is also updating for each CPUs, It should not be changed
 | 
			
		||||
in the same time by other part of the driver.
 | 
			
		||||
 | 
			
		||||
This patch adds spinlock to create the needed critical sections.
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
 | 
			
		||||
Signed-off-by: David S. Miller <davem@davemloft.net>
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
+++ b/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
@@ -370,6 +370,10 @@ struct mvneta_port {
 | 
			
		||||
 	struct net_device *dev;
 | 
			
		||||
 	struct notifier_block cpu_notifier;
 | 
			
		||||
 	int rxq_def;
 | 
			
		||||
+	/* Protect the access to the percpu interrupt registers,
 | 
			
		||||
+	 * ensuring that the configuration remains coherent.
 | 
			
		||||
+	 */
 | 
			
		||||
+	spinlock_t lock;
 | 
			
		||||
 
 | 
			
		||||
 	/* Core clock */
 | 
			
		||||
 	struct clk *clk;
 | 
			
		||||
@@ -2853,6 +2857,12 @@ static void mvneta_percpu_elect(struct m
 | 
			
		||||
 {
 | 
			
		||||
 	int elected_cpu = 0, max_cpu, cpu, i = 0;
 | 
			
		||||
 
 | 
			
		||||
+	/* Electing a CPU must be done in an atomic way: it should be
 | 
			
		||||
+	 * done after or before the removal/insertion of a CPU and
 | 
			
		||||
+	 * this function is not reentrant.
 | 
			
		||||
+	 */
 | 
			
		||||
+	spin_lock(&pp->lock);
 | 
			
		||||
+
 | 
			
		||||
 	/* Use the cpu associated to the rxq when it is online, in all
 | 
			
		||||
 	 * the other cases, use the cpu 0 which can't be offline.
 | 
			
		||||
 	 */
 | 
			
		||||
@@ -2896,6 +2906,7 @@ static void mvneta_percpu_elect(struct m
 | 
			
		||||
 		i++;
 | 
			
		||||
 
 | 
			
		||||
 	}
 | 
			
		||||
+	spin_unlock(&pp->lock);
 | 
			
		||||
 };
 | 
			
		||||
 
 | 
			
		||||
 static int mvneta_percpu_notifier(struct notifier_block *nfb,
 | 
			
		||||
@@ -2950,8 +2961,13 @@ static int mvneta_percpu_notifier(struct
 | 
			
		||||
 	case CPU_DOWN_PREPARE:
 | 
			
		||||
 	case CPU_DOWN_PREPARE_FROZEN:
 | 
			
		||||
 		netif_tx_stop_all_queues(pp->dev);
 | 
			
		||||
+		/* Thanks to this lock we are sure that any pending
 | 
			
		||||
+		 * cpu election is done
 | 
			
		||||
+		 */
 | 
			
		||||
+		spin_lock(&pp->lock);
 | 
			
		||||
 		/* Mask all ethernet port interrupts */
 | 
			
		||||
 		on_each_cpu(mvneta_percpu_mask_interrupt, pp, true);
 | 
			
		||||
+		spin_unlock(&pp->lock);
 | 
			
		||||
 
 | 
			
		||||
 		napi_synchronize(&port->napi);
 | 
			
		||||
 		napi_disable(&port->napi);
 | 
			
		||||
@@ -0,0 +1,128 @@
 | 
			
		||||
From: Gregory CLEMENT <gregory.clement@free-electrons.com>
 | 
			
		||||
Date: Thu, 4 Feb 2016 22:09:29 +0100
 | 
			
		||||
Subject: [PATCH] net: mvneta: Fix race condition during stopping
 | 
			
		||||
 | 
			
		||||
When stopping the port, the CPU notifier are still there whereas the
 | 
			
		||||
mvneta_stop_dev function calls mvneta_percpu_disable() on each CPUs.
 | 
			
		||||
It was possible to have a new CPU coming at this point which could be
 | 
			
		||||
racy.
 | 
			
		||||
 | 
			
		||||
This patch adds a flag preventing executing the code notifier for a new
 | 
			
		||||
CPU when the port is stopping. It also uses the spinlock introduces
 | 
			
		||||
previously. To avoid the deadlock, the lock has been moved outside the
 | 
			
		||||
mvneta_percpu_elect function.
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
 | 
			
		||||
Signed-off-by: David S. Miller <davem@davemloft.net>
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
+++ b/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
@@ -374,6 +374,7 @@ struct mvneta_port {
 | 
			
		||||
 	 * ensuring that the configuration remains coherent.
 | 
			
		||||
 	 */
 | 
			
		||||
 	spinlock_t lock;
 | 
			
		||||
+	bool is_stopped;
 | 
			
		||||
 
 | 
			
		||||
 	/* Core clock */
 | 
			
		||||
 	struct clk *clk;
 | 
			
		||||
@@ -2853,16 +2854,14 @@ static void mvneta_percpu_disable(void *
 | 
			
		||||
 	disable_percpu_irq(pp->dev->irq);
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
+/* Electing a CPU must be done in an atomic way: it should be done
 | 
			
		||||
+ * after or before the removal/insertion of a CPU and this function is
 | 
			
		||||
+ * not reentrant.
 | 
			
		||||
+ */
 | 
			
		||||
 static void mvneta_percpu_elect(struct mvneta_port *pp)
 | 
			
		||||
 {
 | 
			
		||||
 	int elected_cpu = 0, max_cpu, cpu, i = 0;
 | 
			
		||||
 
 | 
			
		||||
-	/* Electing a CPU must be done in an atomic way: it should be
 | 
			
		||||
-	 * done after or before the removal/insertion of a CPU and
 | 
			
		||||
-	 * this function is not reentrant.
 | 
			
		||||
-	 */
 | 
			
		||||
-	spin_lock(&pp->lock);
 | 
			
		||||
-
 | 
			
		||||
 	/* Use the cpu associated to the rxq when it is online, in all
 | 
			
		||||
 	 * the other cases, use the cpu 0 which can't be offline.
 | 
			
		||||
 	 */
 | 
			
		||||
@@ -2906,7 +2905,6 @@ static void mvneta_percpu_elect(struct m
 | 
			
		||||
 		i++;
 | 
			
		||||
 
 | 
			
		||||
 	}
 | 
			
		||||
-	spin_unlock(&pp->lock);
 | 
			
		||||
 };
 | 
			
		||||
 
 | 
			
		||||
 static int mvneta_percpu_notifier(struct notifier_block *nfb,
 | 
			
		||||
@@ -2920,6 +2918,14 @@ static int mvneta_percpu_notifier(struct
 | 
			
		||||
 	switch (action) {
 | 
			
		||||
 	case CPU_ONLINE:
 | 
			
		||||
 	case CPU_ONLINE_FROZEN:
 | 
			
		||||
+		spin_lock(&pp->lock);
 | 
			
		||||
+		/* Configuring the driver for a new CPU while the
 | 
			
		||||
+		 * driver is stopping is racy, so just avoid it.
 | 
			
		||||
+		 */
 | 
			
		||||
+		if (pp->is_stopped) {
 | 
			
		||||
+			spin_unlock(&pp->lock);
 | 
			
		||||
+			break;
 | 
			
		||||
+		}
 | 
			
		||||
 		netif_tx_stop_all_queues(pp->dev);
 | 
			
		||||
 
 | 
			
		||||
 		/* We have to synchronise on tha napi of each CPU
 | 
			
		||||
@@ -2957,6 +2963,7 @@ static int mvneta_percpu_notifier(struct
 | 
			
		||||
 			MVNETA_CAUSE_LINK_CHANGE |
 | 
			
		||||
 			MVNETA_CAUSE_PSC_SYNC_CHANGE);
 | 
			
		||||
 		netif_tx_start_all_queues(pp->dev);
 | 
			
		||||
+		spin_unlock(&pp->lock);
 | 
			
		||||
 		break;
 | 
			
		||||
 	case CPU_DOWN_PREPARE:
 | 
			
		||||
 	case CPU_DOWN_PREPARE_FROZEN:
 | 
			
		||||
@@ -2981,7 +2988,9 @@ static int mvneta_percpu_notifier(struct
 | 
			
		||||
 	case CPU_DEAD:
 | 
			
		||||
 	case CPU_DEAD_FROZEN:
 | 
			
		||||
 		/* Check if a new CPU must be elected now this on is down */
 | 
			
		||||
+		spin_lock(&pp->lock);
 | 
			
		||||
 		mvneta_percpu_elect(pp);
 | 
			
		||||
+		spin_unlock(&pp->lock);
 | 
			
		||||
 		/* Unmask all ethernet port interrupts */
 | 
			
		||||
 		on_each_cpu(mvneta_percpu_unmask_interrupt, pp, true);
 | 
			
		||||
 		mvreg_write(pp, MVNETA_INTR_MISC_MASK,
 | 
			
		||||
@@ -3033,7 +3042,7 @@ static int mvneta_open(struct net_device
 | 
			
		||||
 	 */
 | 
			
		||||
 	on_each_cpu(mvneta_percpu_enable, pp, true);
 | 
			
		||||
 
 | 
			
		||||
-
 | 
			
		||||
+	pp->is_stopped = false;
 | 
			
		||||
 	/* Register a CPU notifier to handle the case where our CPU
 | 
			
		||||
 	 * might be taken offline.
 | 
			
		||||
 	 */
 | 
			
		||||
@@ -3066,9 +3075,18 @@ static int mvneta_stop(struct net_device
 | 
			
		||||
 {
 | 
			
		||||
 	struct mvneta_port *pp = netdev_priv(dev);
 | 
			
		||||
 
 | 
			
		||||
+	/* Inform that we are stopping so we don't want to setup the
 | 
			
		||||
+	 * driver for new CPUs in the notifiers
 | 
			
		||||
+	 */
 | 
			
		||||
+	spin_lock(&pp->lock);
 | 
			
		||||
+	pp->is_stopped = true;
 | 
			
		||||
 	mvneta_stop_dev(pp);
 | 
			
		||||
 	mvneta_mdio_remove(pp);
 | 
			
		||||
 	unregister_cpu_notifier(&pp->cpu_notifier);
 | 
			
		||||
+	/* Now that the notifier are unregistered, we can release le
 | 
			
		||||
+	 * lock
 | 
			
		||||
+	 */
 | 
			
		||||
+	spin_unlock(&pp->lock);
 | 
			
		||||
 	on_each_cpu(mvneta_percpu_disable, pp, true);
 | 
			
		||||
 	free_percpu_irq(dev->irq, pp->ports);
 | 
			
		||||
 	mvneta_cleanup_rxqs(pp);
 | 
			
		||||
@@ -3339,7 +3357,9 @@ static int  mvneta_config_rss(struct mvn
 | 
			
		||||
 	mvreg_write(pp, MVNETA_PORT_CONFIG, val);
 | 
			
		||||
 
 | 
			
		||||
 	/* Update the elected CPU matching the new rxq_def */
 | 
			
		||||
+	spin_lock(&pp->lock);
 | 
			
		||||
 	mvneta_percpu_elect(pp);
 | 
			
		||||
+	spin_unlock(&pp->lock);
 | 
			
		||||
 
 | 
			
		||||
 	/* We have to synchronise on the napi of each CPU */
 | 
			
		||||
 	for_each_online_cpu(cpu) {
 | 
			
		||||
@@ -0,0 +1,56 @@
 | 
			
		||||
From: Jisheng Zhang <jszhang@marvell.com>
 | 
			
		||||
Date: Wed, 20 Jan 2016 19:27:22 +0800
 | 
			
		||||
Subject: [PATCH] net: mvneta: sort the headers in alphabetic order
 | 
			
		||||
 | 
			
		||||
Sorting the headers in alphabetic order will help to reduce the conflict
 | 
			
		||||
when adding new headers in the future.
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Jisheng Zhang <jszhang@marvell.com>
 | 
			
		||||
Acked-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
 | 
			
		||||
Signed-off-by: David S. Miller <davem@davemloft.net>
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
+++ b/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
@@ -11,28 +11,28 @@
 | 
			
		||||
  * warranty of any kind, whether express or implied.
 | 
			
		||||
  */
 | 
			
		||||
 
 | 
			
		||||
-#include <linux/kernel.h>
 | 
			
		||||
-#include <linux/netdevice.h>
 | 
			
		||||
+#include <linux/clk.h>
 | 
			
		||||
+#include <linux/cpu.h>
 | 
			
		||||
 #include <linux/etherdevice.h>
 | 
			
		||||
-#include <linux/platform_device.h>
 | 
			
		||||
-#include <linux/skbuff.h>
 | 
			
		||||
+#include <linux/if_vlan.h>
 | 
			
		||||
 #include <linux/inetdevice.h>
 | 
			
		||||
-#include <linux/mbus.h>
 | 
			
		||||
-#include <linux/module.h>
 | 
			
		||||
 #include <linux/interrupt.h>
 | 
			
		||||
-#include <linux/if_vlan.h>
 | 
			
		||||
-#include <net/ip.h>
 | 
			
		||||
-#include <net/ipv6.h>
 | 
			
		||||
 #include <linux/io.h>
 | 
			
		||||
-#include <net/tso.h>
 | 
			
		||||
+#include <linux/kernel.h>
 | 
			
		||||
+#include <linux/mbus.h>
 | 
			
		||||
+#include <linux/module.h>
 | 
			
		||||
+#include <linux/netdevice.h>
 | 
			
		||||
 #include <linux/of.h>
 | 
			
		||||
+#include <linux/of_address.h>
 | 
			
		||||
 #include <linux/of_irq.h>
 | 
			
		||||
 #include <linux/of_mdio.h>
 | 
			
		||||
 #include <linux/of_net.h>
 | 
			
		||||
-#include <linux/of_address.h>
 | 
			
		||||
 #include <linux/phy.h>
 | 
			
		||||
-#include <linux/clk.h>
 | 
			
		||||
-#include <linux/cpu.h>
 | 
			
		||||
+#include <linux/platform_device.h>
 | 
			
		||||
+#include <linux/skbuff.h>
 | 
			
		||||
+#include <net/ip.h>
 | 
			
		||||
+#include <net/ipv6.h>
 | 
			
		||||
+#include <net/tso.h>
 | 
			
		||||
 
 | 
			
		||||
 /* Registers */
 | 
			
		||||
 #define MVNETA_RXQ_CONFIG_REG(q)                (0x1400 + ((q) << 2))
 | 
			
		||||
@@ -0,0 +1,159 @@
 | 
			
		||||
From: Gregory CLEMENT <gregory.clement@free-electrons.com>
 | 
			
		||||
Date: Mon, 14 Mar 2016 09:39:04 +0100
 | 
			
		||||
Subject: [PATCH] net: add a hardware buffer management helper API
 | 
			
		||||
 | 
			
		||||
This basic implementation allows to share code between driver using
 | 
			
		||||
hardware buffer management. As the code is hardware agnostic, there is
 | 
			
		||||
few helpers, most of the optimization brought by the an HW BM has to be
 | 
			
		||||
done at driver level.
 | 
			
		||||
 | 
			
		||||
Tested-by: Sebastian Careba <nitroshift@yahoo.com>
 | 
			
		||||
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
 | 
			
		||||
Signed-off-by: David S. Miller <davem@davemloft.net>
 | 
			
		||||
---
 | 
			
		||||
 create mode 100644 include/net/hwbm.h
 | 
			
		||||
 create mode 100644 net/core/hwbm.c
 | 
			
		||||
 | 
			
		||||
--- /dev/null
 | 
			
		||||
+++ b/include/net/hwbm.h
 | 
			
		||||
@@ -0,0 +1,28 @@
 | 
			
		||||
+#ifndef _HWBM_H
 | 
			
		||||
+#define _HWBM_H
 | 
			
		||||
+
 | 
			
		||||
+struct hwbm_pool {
 | 
			
		||||
+	/* Capacity of the pool */
 | 
			
		||||
+	int size;
 | 
			
		||||
+	/* Size of the buffers managed */
 | 
			
		||||
+	int frag_size;
 | 
			
		||||
+	/* Number of buffers currently used by this pool */
 | 
			
		||||
+	int buf_num;
 | 
			
		||||
+	/* constructor called during alocation */
 | 
			
		||||
+	int (*construct)(struct hwbm_pool *bm_pool, void *buf);
 | 
			
		||||
+	/* protect acces to the buffer counter*/
 | 
			
		||||
+	spinlock_t lock;
 | 
			
		||||
+	/* private data */
 | 
			
		||||
+	void *priv;
 | 
			
		||||
+};
 | 
			
		||||
+#ifdef CONFIG_HWBM
 | 
			
		||||
+void hwbm_buf_free(struct hwbm_pool *bm_pool, void *buf);
 | 
			
		||||
+int hwbm_pool_refill(struct hwbm_pool *bm_pool, gfp_t gfp);
 | 
			
		||||
+int hwbm_pool_add(struct hwbm_pool *bm_pool, unsigned int buf_num, gfp_t gfp);
 | 
			
		||||
+#else
 | 
			
		||||
+void hwbm_buf_free(struct hwbm_pool *bm_pool, void *buf) {}
 | 
			
		||||
+int hwbm_pool_refill(struct hwbm_pool *bm_pool, gfp_t gfp) { return 0; }
 | 
			
		||||
+int hwbm_pool_add(struct hwbm_pool *bm_pool, unsigned int buf_num, gfp_t gfp)
 | 
			
		||||
+{ return 0; }
 | 
			
		||||
+#endif /* CONFIG_HWBM */
 | 
			
		||||
+#endif /* _HWBM_H */
 | 
			
		||||
--- a/net/Kconfig
 | 
			
		||||
+++ b/net/Kconfig
 | 
			
		||||
@@ -259,6 +259,9 @@ config XPS
 | 
			
		||||
 	depends on SMP
 | 
			
		||||
 	default y
 | 
			
		||||
 
 | 
			
		||||
+config HWBM
 | 
			
		||||
+	bool
 | 
			
		||||
+
 | 
			
		||||
 config CGROUP_NET_PRIO
 | 
			
		||||
 	bool "Network priority cgroup"
 | 
			
		||||
 	depends on CGROUPS
 | 
			
		||||
--- a/net/core/Makefile
 | 
			
		||||
+++ b/net/core/Makefile
 | 
			
		||||
@@ -14,6 +14,7 @@ obj-y		     += dev.o ethtool.o dev_addr_
 | 
			
		||||
 obj-$(CONFIG_SOCK_DIAG) += sock_diag.o
 | 
			
		||||
 obj-$(CONFIG_XFRM) += flow.o
 | 
			
		||||
 obj-y += net-sysfs.o
 | 
			
		||||
+obj-$(CONFIG_HWBM) += hwbm.o
 | 
			
		||||
 obj-$(CONFIG_PROC_FS) += net-procfs.o
 | 
			
		||||
 obj-$(CONFIG_NET_PKTGEN) += pktgen.o
 | 
			
		||||
 obj-$(CONFIG_NETPOLL) += netpoll.o
 | 
			
		||||
--- /dev/null
 | 
			
		||||
+++ b/net/core/hwbm.c
 | 
			
		||||
@@ -0,0 +1,87 @@
 | 
			
		||||
+/* Support for hardware buffer manager.
 | 
			
		||||
+ *
 | 
			
		||||
+ * Copyright (C) 2016 Marvell
 | 
			
		||||
+ *
 | 
			
		||||
+ * Gregory CLEMENT <gregory.clement@free-electrons.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.
 | 
			
		||||
+ */
 | 
			
		||||
+#include <linux/kernel.h>
 | 
			
		||||
+#include <linux/printk.h>
 | 
			
		||||
+#include <linux/skbuff.h>
 | 
			
		||||
+#include <net/hwbm.h>
 | 
			
		||||
+
 | 
			
		||||
+void hwbm_buf_free(struct hwbm_pool *bm_pool, void *buf)
 | 
			
		||||
+{
 | 
			
		||||
+	if (likely(bm_pool->frag_size <= PAGE_SIZE))
 | 
			
		||||
+		skb_free_frag(buf);
 | 
			
		||||
+	else
 | 
			
		||||
+		kfree(buf);
 | 
			
		||||
+}
 | 
			
		||||
+EXPORT_SYMBOL_GPL(hwbm_buf_free);
 | 
			
		||||
+
 | 
			
		||||
+/* Refill processing for HW buffer management */
 | 
			
		||||
+int hwbm_pool_refill(struct hwbm_pool *bm_pool, gfp_t gfp)
 | 
			
		||||
+{
 | 
			
		||||
+	int frag_size = bm_pool->frag_size;
 | 
			
		||||
+	void *buf;
 | 
			
		||||
+
 | 
			
		||||
+	if (likely(frag_size <= PAGE_SIZE))
 | 
			
		||||
+		buf = netdev_alloc_frag(frag_size);
 | 
			
		||||
+	else
 | 
			
		||||
+		buf = kmalloc(frag_size, gfp);
 | 
			
		||||
+
 | 
			
		||||
+	if (!buf)
 | 
			
		||||
+		return -ENOMEM;
 | 
			
		||||
+
 | 
			
		||||
+	if (bm_pool->construct)
 | 
			
		||||
+		if (bm_pool->construct(bm_pool, buf)) {
 | 
			
		||||
+			hwbm_buf_free(bm_pool, buf);
 | 
			
		||||
+			return -ENOMEM;
 | 
			
		||||
+		}
 | 
			
		||||
+
 | 
			
		||||
+	return 0;
 | 
			
		||||
+}
 | 
			
		||||
+EXPORT_SYMBOL_GPL(hwbm_pool_refill);
 | 
			
		||||
+
 | 
			
		||||
+int hwbm_pool_add(struct hwbm_pool *bm_pool, unsigned int buf_num, gfp_t gfp)
 | 
			
		||||
+{
 | 
			
		||||
+	int err, i;
 | 
			
		||||
+	unsigned long flags;
 | 
			
		||||
+
 | 
			
		||||
+	spin_lock_irqsave(&bm_pool->lock, flags);
 | 
			
		||||
+	if (bm_pool->buf_num == bm_pool->size) {
 | 
			
		||||
+		pr_warn("pool already filled\n");
 | 
			
		||||
+		return bm_pool->buf_num;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	if (buf_num + bm_pool->buf_num > bm_pool->size) {
 | 
			
		||||
+		pr_warn("cannot allocate %d buffers for pool\n",
 | 
			
		||||
+			buf_num);
 | 
			
		||||
+		return 0;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	if ((buf_num + bm_pool->buf_num) < bm_pool->buf_num) {
 | 
			
		||||
+		pr_warn("Adding %d buffers to the %d current buffers will overflow\n",
 | 
			
		||||
+			buf_num,  bm_pool->buf_num);
 | 
			
		||||
+		return 0;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	for (i = 0; i < buf_num; i++) {
 | 
			
		||||
+		err = hwbm_pool_refill(bm_pool, gfp);
 | 
			
		||||
+		if (err < 0)
 | 
			
		||||
+			break;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	/* Update BM driver with number of buffers added to pool */
 | 
			
		||||
+	bm_pool->buf_num += i;
 | 
			
		||||
+
 | 
			
		||||
+	pr_debug("hwpm pool: %d of %d buffers added\n", i, buf_num);
 | 
			
		||||
+	spin_unlock_irqrestore(&bm_pool->lock, flags);
 | 
			
		||||
+
 | 
			
		||||
+	return i;
 | 
			
		||||
+}
 | 
			
		||||
+EXPORT_SYMBOL_GPL(hwbm_pool_add);
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -0,0 +1,359 @@
 | 
			
		||||
From: Gregory CLEMENT <gregory.clement@free-electrons.com>
 | 
			
		||||
Date: Mon, 14 Mar 2016 09:39:05 +0100
 | 
			
		||||
Subject: [PATCH] net: mvneta: Use the new hwbm framework
 | 
			
		||||
 | 
			
		||||
Now that the hardware buffer management framework had been introduced,
 | 
			
		||||
let's use it.
 | 
			
		||||
 | 
			
		||||
Tested-by: Sebastian Careba <nitroshift@yahoo.com>
 | 
			
		||||
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
 | 
			
		||||
Signed-off-by: David S. Miller <davem@davemloft.net>
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/ethernet/marvell/Kconfig
 | 
			
		||||
+++ b/drivers/net/ethernet/marvell/Kconfig
 | 
			
		||||
@@ -43,6 +43,7 @@ config MVMDIO
 | 
			
		||||
 config MVNETA_BM
 | 
			
		||||
 	tristate "Marvell Armada 38x/XP network interface BM support"
 | 
			
		||||
 	depends on MVNETA
 | 
			
		||||
+	select HWBM
 | 
			
		||||
 	---help---
 | 
			
		||||
 	  This driver supports auxiliary block of the network
 | 
			
		||||
 	  interface units in the Marvell ARMADA XP and ARMADA 38x SoC
 | 
			
		||||
--- a/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
+++ b/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
@@ -30,6 +30,7 @@
 | 
			
		||||
 #include <linux/phy.h>
 | 
			
		||||
 #include <linux/platform_device.h>
 | 
			
		||||
 #include <linux/skbuff.h>
 | 
			
		||||
+#include <net/hwbm.h>
 | 
			
		||||
 #include "mvneta_bm.h"
 | 
			
		||||
 #include <net/ip.h>
 | 
			
		||||
 #include <net/ipv6.h>
 | 
			
		||||
@@ -1024,11 +1025,12 @@ static int mvneta_bm_port_init(struct pl
 | 
			
		||||
 static void mvneta_bm_update_mtu(struct mvneta_port *pp, int mtu)
 | 
			
		||||
 {
 | 
			
		||||
 	struct mvneta_bm_pool *bm_pool = pp->pool_long;
 | 
			
		||||
+	struct hwbm_pool *hwbm_pool = &bm_pool->hwbm_pool;
 | 
			
		||||
 	int num;
 | 
			
		||||
 
 | 
			
		||||
 	/* Release all buffers from long pool */
 | 
			
		||||
 	mvneta_bm_bufs_free(pp->bm_priv, bm_pool, 1 << pp->id);
 | 
			
		||||
-	if (bm_pool->buf_num) {
 | 
			
		||||
+	if (hwbm_pool->buf_num) {
 | 
			
		||||
 		WARN(1, "cannot free all buffers in pool %d\n",
 | 
			
		||||
 		     bm_pool->id);
 | 
			
		||||
 		goto bm_mtu_err;
 | 
			
		||||
@@ -1036,14 +1038,14 @@ static void mvneta_bm_update_mtu(struct
 | 
			
		||||
 
 | 
			
		||||
 	bm_pool->pkt_size = MVNETA_RX_PKT_SIZE(mtu);
 | 
			
		||||
 	bm_pool->buf_size = MVNETA_RX_BUF_SIZE(bm_pool->pkt_size);
 | 
			
		||||
-	bm_pool->frag_size = SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) +
 | 
			
		||||
-			  SKB_DATA_ALIGN(MVNETA_RX_BUF_SIZE(bm_pool->pkt_size));
 | 
			
		||||
+	hwbm_pool->frag_size = SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) +
 | 
			
		||||
+			SKB_DATA_ALIGN(MVNETA_RX_BUF_SIZE(bm_pool->pkt_size));
 | 
			
		||||
 
 | 
			
		||||
 	/* Fill entire long pool */
 | 
			
		||||
-	num = mvneta_bm_bufs_add(pp->bm_priv, bm_pool, bm_pool->size);
 | 
			
		||||
-	if (num != bm_pool->size) {
 | 
			
		||||
+	num = hwbm_pool_add(hwbm_pool, hwbm_pool->size, GFP_ATOMIC);
 | 
			
		||||
+	if (num != hwbm_pool->size) {
 | 
			
		||||
 		WARN(1, "pool %d: %d of %d allocated\n",
 | 
			
		||||
-		     bm_pool->id, num, bm_pool->size);
 | 
			
		||||
+		     bm_pool->id, num, hwbm_pool->size);
 | 
			
		||||
 		goto bm_mtu_err;
 | 
			
		||||
 	}
 | 
			
		||||
 	mvneta_bm_pool_bufsize_set(pp, bm_pool->buf_size, bm_pool->id);
 | 
			
		||||
@@ -2064,14 +2066,14 @@ err_drop_frame:
 | 
			
		||||
 		}
 | 
			
		||||
 
 | 
			
		||||
 		/* Refill processing */
 | 
			
		||||
-		err = mvneta_bm_pool_refill(pp->bm_priv, bm_pool);
 | 
			
		||||
+		err = hwbm_pool_refill(&bm_pool->hwbm_pool, GFP_ATOMIC);
 | 
			
		||||
 		if (err) {
 | 
			
		||||
 			netdev_err(dev, "Linux processing - Can't refill\n");
 | 
			
		||||
 			rxq->missed++;
 | 
			
		||||
 			goto err_drop_frame_ret_pool;
 | 
			
		||||
 		}
 | 
			
		||||
 
 | 
			
		||||
-		frag_size = bm_pool->frag_size;
 | 
			
		||||
+		frag_size = bm_pool->hwbm_pool.frag_size;
 | 
			
		||||
 
 | 
			
		||||
 		skb = build_skb(data, frag_size > PAGE_SIZE ? 0 : frag_size);
 | 
			
		||||
 
 | 
			
		||||
--- a/drivers/net/ethernet/marvell/mvneta_bm.c
 | 
			
		||||
+++ b/drivers/net/ethernet/marvell/mvneta_bm.c
 | 
			
		||||
@@ -10,16 +10,17 @@
 | 
			
		||||
  * warranty of any kind, whether express or implied.
 | 
			
		||||
  */
 | 
			
		||||
 
 | 
			
		||||
-#include <linux/kernel.h>
 | 
			
		||||
+#include <linux/clk.h>
 | 
			
		||||
 #include <linux/genalloc.h>
 | 
			
		||||
-#include <linux/platform_device.h>
 | 
			
		||||
-#include <linux/netdevice.h>
 | 
			
		||||
-#include <linux/skbuff.h>
 | 
			
		||||
+#include <linux/io.h>
 | 
			
		||||
+#include <linux/kernel.h>
 | 
			
		||||
 #include <linux/mbus.h>
 | 
			
		||||
 #include <linux/module.h>
 | 
			
		||||
-#include <linux/io.h>
 | 
			
		||||
+#include <linux/netdevice.h>
 | 
			
		||||
 #include <linux/of.h>
 | 
			
		||||
-#include <linux/clk.h>
 | 
			
		||||
+#include <linux/platform_device.h>
 | 
			
		||||
+#include <linux/skbuff.h>
 | 
			
		||||
+#include <net/hwbm.h>
 | 
			
		||||
 #include "mvneta_bm.h"
 | 
			
		||||
 
 | 
			
		||||
 #define MVNETA_BM_DRIVER_NAME "mvneta_bm"
 | 
			
		||||
@@ -88,17 +89,13 @@ static void mvneta_bm_pool_target_set(st
 | 
			
		||||
 	mvneta_bm_write(priv, MVNETA_BM_XBAR_POOL_REG(pool_id), val);
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
-/* Allocate skb for BM pool */
 | 
			
		||||
-void *mvneta_buf_alloc(struct mvneta_bm *priv, struct mvneta_bm_pool *bm_pool,
 | 
			
		||||
-		       dma_addr_t *buf_phys_addr)
 | 
			
		||||
+int mvneta_bm_construct(struct hwbm_pool *hwbm_pool, void *buf)
 | 
			
		||||
 {
 | 
			
		||||
-	void *buf;
 | 
			
		||||
+	struct mvneta_bm_pool *bm_pool =
 | 
			
		||||
+		(struct mvneta_bm_pool *)hwbm_pool->priv;
 | 
			
		||||
+	struct mvneta_bm *priv = bm_pool->priv;
 | 
			
		||||
 	dma_addr_t phys_addr;
 | 
			
		||||
 
 | 
			
		||||
-	buf = mvneta_frag_alloc(bm_pool->frag_size);
 | 
			
		||||
-	if (!buf)
 | 
			
		||||
-		return NULL;
 | 
			
		||||
-
 | 
			
		||||
 	/* In order to update buf_cookie field of RX descriptor properly,
 | 
			
		||||
 	 * BM hardware expects buf virtual address to be placed in the
 | 
			
		||||
 	 * first four bytes of mapped buffer.
 | 
			
		||||
@@ -106,75 +103,13 @@ void *mvneta_buf_alloc(struct mvneta_bm
 | 
			
		||||
 	*(u32 *)buf = (u32)buf;
 | 
			
		||||
 	phys_addr = dma_map_single(&priv->pdev->dev, buf, bm_pool->buf_size,
 | 
			
		||||
 				   DMA_FROM_DEVICE);
 | 
			
		||||
-	if (unlikely(dma_mapping_error(&priv->pdev->dev, phys_addr))) {
 | 
			
		||||
-		mvneta_frag_free(bm_pool->frag_size, buf);
 | 
			
		||||
-		return NULL;
 | 
			
		||||
-	}
 | 
			
		||||
-	*buf_phys_addr = phys_addr;
 | 
			
		||||
-
 | 
			
		||||
-	return buf;
 | 
			
		||||
-}
 | 
			
		||||
-
 | 
			
		||||
-/* Refill processing for HW buffer management */
 | 
			
		||||
-int mvneta_bm_pool_refill(struct mvneta_bm *priv,
 | 
			
		||||
-			  struct mvneta_bm_pool *bm_pool)
 | 
			
		||||
-{
 | 
			
		||||
-	dma_addr_t buf_phys_addr;
 | 
			
		||||
-	void *buf;
 | 
			
		||||
-
 | 
			
		||||
-	buf = mvneta_buf_alloc(priv, bm_pool, &buf_phys_addr);
 | 
			
		||||
-	if (!buf)
 | 
			
		||||
+	if (unlikely(dma_mapping_error(&priv->pdev->dev, phys_addr)))
 | 
			
		||||
 		return -ENOMEM;
 | 
			
		||||
 
 | 
			
		||||
-	mvneta_bm_pool_put_bp(priv, bm_pool, buf_phys_addr);
 | 
			
		||||
-
 | 
			
		||||
+	mvneta_bm_pool_put_bp(priv, bm_pool, phys_addr);
 | 
			
		||||
 	return 0;
 | 
			
		||||
 }
 | 
			
		||||
-EXPORT_SYMBOL_GPL(mvneta_bm_pool_refill);
 | 
			
		||||
-
 | 
			
		||||
-/* Allocate buffers for the pool */
 | 
			
		||||
-int mvneta_bm_bufs_add(struct mvneta_bm *priv, struct mvneta_bm_pool *bm_pool,
 | 
			
		||||
-		       int buf_num)
 | 
			
		||||
-{
 | 
			
		||||
-	int err, i;
 | 
			
		||||
-
 | 
			
		||||
-	if (bm_pool->buf_num == bm_pool->size) {
 | 
			
		||||
-		dev_dbg(&priv->pdev->dev, "pool %d already filled\n",
 | 
			
		||||
-			bm_pool->id);
 | 
			
		||||
-		return bm_pool->buf_num;
 | 
			
		||||
-	}
 | 
			
		||||
-
 | 
			
		||||
-	if (buf_num < 0 ||
 | 
			
		||||
-	    (buf_num + bm_pool->buf_num > bm_pool->size)) {
 | 
			
		||||
-		dev_err(&priv->pdev->dev,
 | 
			
		||||
-			"cannot allocate %d buffers for pool %d\n",
 | 
			
		||||
-			buf_num, bm_pool->id);
 | 
			
		||||
-		return 0;
 | 
			
		||||
-	}
 | 
			
		||||
-
 | 
			
		||||
-	for (i = 0; i < buf_num; i++) {
 | 
			
		||||
-		err = mvneta_bm_pool_refill(priv, bm_pool);
 | 
			
		||||
-		if (err < 0)
 | 
			
		||||
-			break;
 | 
			
		||||
-	}
 | 
			
		||||
-
 | 
			
		||||
-	/* Update BM driver with number of buffers added to pool */
 | 
			
		||||
-	bm_pool->buf_num += i;
 | 
			
		||||
-
 | 
			
		||||
-	dev_dbg(&priv->pdev->dev,
 | 
			
		||||
-		"%s pool %d: pkt_size=%4d, buf_size=%4d, frag_size=%4d\n",
 | 
			
		||||
-		bm_pool->type == MVNETA_BM_SHORT ? "short" : "long",
 | 
			
		||||
-		bm_pool->id, bm_pool->pkt_size, bm_pool->buf_size,
 | 
			
		||||
-		bm_pool->frag_size);
 | 
			
		||||
-
 | 
			
		||||
-	dev_dbg(&priv->pdev->dev,
 | 
			
		||||
-		"%s pool %d: %d of %d buffers added\n",
 | 
			
		||||
-		bm_pool->type == MVNETA_BM_SHORT ? "short" : "long",
 | 
			
		||||
-		bm_pool->id, i, buf_num);
 | 
			
		||||
-
 | 
			
		||||
-	return i;
 | 
			
		||||
-}
 | 
			
		||||
-EXPORT_SYMBOL_GPL(mvneta_bm_bufs_add);
 | 
			
		||||
+EXPORT_SYMBOL_GPL(mvneta_bm_construct);
 | 
			
		||||
 
 | 
			
		||||
 /* Create pool */
 | 
			
		||||
 static int mvneta_bm_pool_create(struct mvneta_bm *priv,
 | 
			
		||||
@@ -183,8 +118,7 @@ static int mvneta_bm_pool_create(struct
 | 
			
		||||
 	struct platform_device *pdev = priv->pdev;
 | 
			
		||||
 	u8 target_id, attr;
 | 
			
		||||
 	int size_bytes, err;
 | 
			
		||||
-
 | 
			
		||||
-	size_bytes = sizeof(u32) * bm_pool->size;
 | 
			
		||||
+	size_bytes = sizeof(u32) * bm_pool->hwbm_pool.size;
 | 
			
		||||
 	bm_pool->virt_addr = dma_alloc_coherent(&pdev->dev, size_bytes,
 | 
			
		||||
 						&bm_pool->phys_addr,
 | 
			
		||||
 						GFP_KERNEL);
 | 
			
		||||
@@ -245,11 +179,16 @@ struct mvneta_bm_pool *mvneta_bm_pool_us
 | 
			
		||||
 
 | 
			
		||||
 	/* Allocate buffers in case BM pool hasn't been used yet */
 | 
			
		||||
 	if (new_pool->type == MVNETA_BM_FREE) {
 | 
			
		||||
+		struct hwbm_pool *hwbm_pool = &new_pool->hwbm_pool;
 | 
			
		||||
+
 | 
			
		||||
+		new_pool->priv = priv;
 | 
			
		||||
 		new_pool->type = type;
 | 
			
		||||
 		new_pool->buf_size = MVNETA_RX_BUF_SIZE(new_pool->pkt_size);
 | 
			
		||||
-		new_pool->frag_size =
 | 
			
		||||
+		hwbm_pool->frag_size =
 | 
			
		||||
 			SKB_DATA_ALIGN(MVNETA_RX_BUF_SIZE(new_pool->pkt_size)) +
 | 
			
		||||
 			SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
 | 
			
		||||
+		hwbm_pool->construct = mvneta_bm_construct;
 | 
			
		||||
+		hwbm_pool->priv = new_pool;
 | 
			
		||||
 
 | 
			
		||||
 		/* Create new pool */
 | 
			
		||||
 		err = mvneta_bm_pool_create(priv, new_pool);
 | 
			
		||||
@@ -260,10 +199,10 @@ struct mvneta_bm_pool *mvneta_bm_pool_us
 | 
			
		||||
 		}
 | 
			
		||||
 
 | 
			
		||||
 		/* Allocate buffers for this pool */
 | 
			
		||||
-		num = mvneta_bm_bufs_add(priv, new_pool, new_pool->size);
 | 
			
		||||
-		if (num != new_pool->size) {
 | 
			
		||||
+		num = hwbm_pool_add(hwbm_pool, hwbm_pool->size, GFP_ATOMIC);
 | 
			
		||||
+		if (num != hwbm_pool->size) {
 | 
			
		||||
 			WARN(1, "pool %d: %d of %d allocated\n",
 | 
			
		||||
-			     new_pool->id, num, new_pool->size);
 | 
			
		||||
+			     new_pool->id, num, hwbm_pool->size);
 | 
			
		||||
 			return NULL;
 | 
			
		||||
 		}
 | 
			
		||||
 	}
 | 
			
		||||
@@ -284,7 +223,7 @@ void mvneta_bm_bufs_free(struct mvneta_b
 | 
			
		||||
 
 | 
			
		||||
 	mvneta_bm_config_set(priv, MVNETA_BM_EMPTY_LIMIT_MASK);
 | 
			
		||||
 
 | 
			
		||||
-	for (i = 0; i < bm_pool->buf_num; i++) {
 | 
			
		||||
+	for (i = 0; i < bm_pool->hwbm_pool.buf_num; i++) {
 | 
			
		||||
 		dma_addr_t buf_phys_addr;
 | 
			
		||||
 		u32 *vaddr;
 | 
			
		||||
 
 | 
			
		||||
@@ -303,13 +242,13 @@ void mvneta_bm_bufs_free(struct mvneta_b
 | 
			
		||||
 
 | 
			
		||||
 		dma_unmap_single(&priv->pdev->dev, buf_phys_addr,
 | 
			
		||||
 				 bm_pool->buf_size, DMA_FROM_DEVICE);
 | 
			
		||||
-		mvneta_frag_free(bm_pool->frag_size, vaddr);
 | 
			
		||||
+		hwbm_buf_free(&bm_pool->hwbm_pool, vaddr);
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
 	mvneta_bm_config_clear(priv, MVNETA_BM_EMPTY_LIMIT_MASK);
 | 
			
		||||
 
 | 
			
		||||
 	/* Update BM driver with number of buffers removed from pool */
 | 
			
		||||
-	bm_pool->buf_num -= i;
 | 
			
		||||
+	bm_pool->hwbm_pool.buf_num -= i;
 | 
			
		||||
 }
 | 
			
		||||
 EXPORT_SYMBOL_GPL(mvneta_bm_bufs_free);
 | 
			
		||||
 
 | 
			
		||||
@@ -317,6 +256,7 @@ EXPORT_SYMBOL_GPL(mvneta_bm_bufs_free);
 | 
			
		||||
 void mvneta_bm_pool_destroy(struct mvneta_bm *priv,
 | 
			
		||||
 			    struct mvneta_bm_pool *bm_pool, u8 port_map)
 | 
			
		||||
 {
 | 
			
		||||
+	struct hwbm_pool *hwbm_pool = &bm_pool->hwbm_pool;
 | 
			
		||||
 	bm_pool->port_map &= ~port_map;
 | 
			
		||||
 	if (bm_pool->port_map)
 | 
			
		||||
 		return;
 | 
			
		||||
@@ -324,11 +264,12 @@ void mvneta_bm_pool_destroy(struct mvnet
 | 
			
		||||
 	bm_pool->type = MVNETA_BM_FREE;
 | 
			
		||||
 
 | 
			
		||||
 	mvneta_bm_bufs_free(priv, bm_pool, port_map);
 | 
			
		||||
-	if (bm_pool->buf_num)
 | 
			
		||||
+	if (hwbm_pool->buf_num)
 | 
			
		||||
 		WARN(1, "cannot free all buffers in pool %d\n", bm_pool->id);
 | 
			
		||||
 
 | 
			
		||||
 	if (bm_pool->virt_addr) {
 | 
			
		||||
-		dma_free_coherent(&priv->pdev->dev, sizeof(u32) * bm_pool->size,
 | 
			
		||||
+		dma_free_coherent(&priv->pdev->dev,
 | 
			
		||||
+				  sizeof(u32) * hwbm_pool->size,
 | 
			
		||||
 				  bm_pool->virt_addr, bm_pool->phys_addr);
 | 
			
		||||
 		bm_pool->virt_addr = NULL;
 | 
			
		||||
 	}
 | 
			
		||||
@@ -381,10 +322,10 @@ static void mvneta_bm_pools_init(struct
 | 
			
		||||
 				 MVNETA_BM_POOL_CAP_ALIGN));
 | 
			
		||||
 			size = ALIGN(size, MVNETA_BM_POOL_CAP_ALIGN);
 | 
			
		||||
 		}
 | 
			
		||||
-		bm_pool->size = size;
 | 
			
		||||
+		bm_pool->hwbm_pool.size = size;
 | 
			
		||||
 
 | 
			
		||||
 		mvneta_bm_write(priv, MVNETA_BM_POOL_SIZE_REG(i),
 | 
			
		||||
-				bm_pool->size);
 | 
			
		||||
+				bm_pool->hwbm_pool.size);
 | 
			
		||||
 
 | 
			
		||||
 		/* Obtain custom pkt_size from DT */
 | 
			
		||||
 		sprintf(prop, "pool%d,pkt-size", i);
 | 
			
		||||
--- a/drivers/net/ethernet/marvell/mvneta_bm.h
 | 
			
		||||
+++ b/drivers/net/ethernet/marvell/mvneta_bm.h
 | 
			
		||||
@@ -108,20 +108,15 @@ struct mvneta_bm {
 | 
			
		||||
 };
 | 
			
		||||
 
 | 
			
		||||
 struct mvneta_bm_pool {
 | 
			
		||||
+	struct hwbm_pool hwbm_pool;
 | 
			
		||||
 	/* Pool number in the range 0-3 */
 | 
			
		||||
 	u8 id;
 | 
			
		||||
 	enum mvneta_bm_type type;
 | 
			
		||||
 
 | 
			
		||||
-	/* Buffer Pointers Pool External (BPPE) size in number of bytes */
 | 
			
		||||
-	int size;
 | 
			
		||||
-	/* Number of buffers used by this pool */
 | 
			
		||||
-	int buf_num;
 | 
			
		||||
-	/* Pool buffer size */
 | 
			
		||||
-	int buf_size;
 | 
			
		||||
 	/* Packet size */
 | 
			
		||||
 	int pkt_size;
 | 
			
		||||
-	/* Single frag size */
 | 
			
		||||
-	u32 frag_size;
 | 
			
		||||
+	/* Size of the buffer acces through DMA*/
 | 
			
		||||
+	u32 buf_size;
 | 
			
		||||
 
 | 
			
		||||
 	/* BPPE virtual base address */
 | 
			
		||||
 	u32 *virt_addr;
 | 
			
		||||
@@ -143,8 +138,7 @@ void mvneta_bm_pool_destroy(struct mvnet
 | 
			
		||||
 			    struct mvneta_bm_pool *bm_pool, u8 port_map);
 | 
			
		||||
 void mvneta_bm_bufs_free(struct mvneta_bm *priv, struct mvneta_bm_pool *bm_pool,
 | 
			
		||||
 			 u8 port_map);
 | 
			
		||||
-int mvneta_bm_bufs_add(struct mvneta_bm *priv, struct mvneta_bm_pool *bm_pool,
 | 
			
		||||
-		       int buf_num);
 | 
			
		||||
+int mvneta_bm_construct(struct hwbm_pool *hwbm_pool, void *buf);
 | 
			
		||||
 int mvneta_bm_pool_refill(struct mvneta_bm *priv,
 | 
			
		||||
 			  struct mvneta_bm_pool *bm_pool);
 | 
			
		||||
 struct mvneta_bm_pool *mvneta_bm_pool_use(struct mvneta_bm *priv, u8 pool_id,
 | 
			
		||||
@@ -170,8 +164,7 @@ void mvneta_bm_pool_destroy(struct mvnet
 | 
			
		||||
 			    struct mvneta_bm_pool *bm_pool, u8 port_map) {}
 | 
			
		||||
 void mvneta_bm_bufs_free(struct mvneta_bm *priv, struct mvneta_bm_pool *bm_pool,
 | 
			
		||||
 			 u8 port_map) {}
 | 
			
		||||
-int mvneta_bm_bufs_add(struct mvneta_bm *priv, struct mvneta_bm_pool *bm_pool,
 | 
			
		||||
-		       int buf_num) { return 0; }
 | 
			
		||||
+int mvneta_bm_construct(struct hwbm_pool *hwbm_pool, void *buf) { return 0; }
 | 
			
		||||
 int mvneta_bm_pool_refill(struct mvneta_bm *priv,
 | 
			
		||||
 			  struct mvneta_bm_pool *bm_pool) {return 0; }
 | 
			
		||||
 struct mvneta_bm_pool *mvneta_bm_pool_use(struct mvneta_bm *priv, u8 pool_id,
 | 
			
		||||
@@ -0,0 +1,52 @@
 | 
			
		||||
From: Gregory CLEMENT <gregory.clement@free-electrons.com>
 | 
			
		||||
Date: Sat, 12 Mar 2016 18:44:17 +0100
 | 
			
		||||
Subject: [PATCH] net: mvneta: Fix spinlock usage
 | 
			
		||||
 | 
			
		||||
In the previous patch, the spinlock was not initialized. While it didn't
 | 
			
		||||
cause any trouble yet it could be a problem to use it uninitialized.
 | 
			
		||||
 | 
			
		||||
The most annoying part was the critical section protected by the spinlock
 | 
			
		||||
in mvneta_stop(). Some of the functions could sleep as pointed when
 | 
			
		||||
activated CONFIG_DEBUG_ATOMIC_SLEEP. Actually, in mvneta_stop() we only
 | 
			
		||||
need to protect the is_stopped flagged, indeed the code of the notifier
 | 
			
		||||
for CPU online is protected by the same spinlock, so when we get the
 | 
			
		||||
lock, the notifer work is done.
 | 
			
		||||
 | 
			
		||||
Reported-by: Patrick Uiterwijk <patrick@puiterwijk.org>
 | 
			
		||||
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
 | 
			
		||||
Signed-off-by: David S. Miller <davem@davemloft.net>
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
+++ b/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
@@ -3484,17 +3484,17 @@ static int mvneta_stop(struct net_device
 | 
			
		||||
 	struct mvneta_port *pp = netdev_priv(dev);
 | 
			
		||||
 
 | 
			
		||||
 	/* Inform that we are stopping so we don't want to setup the
 | 
			
		||||
-	 * driver for new CPUs in the notifiers
 | 
			
		||||
+	 * driver for new CPUs in the notifiers. The code of the
 | 
			
		||||
+	 * notifier for CPU online is protected by the same spinlock,
 | 
			
		||||
+	 * so when we get the lock, the notifer work is done.
 | 
			
		||||
 	 */
 | 
			
		||||
 	spin_lock(&pp->lock);
 | 
			
		||||
 	pp->is_stopped = true;
 | 
			
		||||
+	spin_unlock(&pp->lock);
 | 
			
		||||
+
 | 
			
		||||
 	mvneta_stop_dev(pp);
 | 
			
		||||
 	mvneta_mdio_remove(pp);
 | 
			
		||||
 	unregister_cpu_notifier(&pp->cpu_notifier);
 | 
			
		||||
-	/* Now that the notifier are unregistered, we can release le
 | 
			
		||||
-	 * lock
 | 
			
		||||
-	 */
 | 
			
		||||
-	spin_unlock(&pp->lock);
 | 
			
		||||
 	on_each_cpu(mvneta_percpu_disable, pp, true);
 | 
			
		||||
 	free_percpu_irq(dev->irq, pp->ports);
 | 
			
		||||
 	mvneta_cleanup_rxqs(pp);
 | 
			
		||||
@@ -4027,6 +4027,7 @@ static int mvneta_probe(struct platform_
 | 
			
		||||
 	dev->ethtool_ops = &mvneta_eth_tool_ops;
 | 
			
		||||
 
 | 
			
		||||
 	pp = netdev_priv(dev);
 | 
			
		||||
+	spin_lock_init(&pp->lock);
 | 
			
		||||
 	pp->phy_node = phy_node;
 | 
			
		||||
 	pp->phy_interface = phy_mode;
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,33 @@
 | 
			
		||||
From: Dmitri Epshtein <dima@marvell.com>
 | 
			
		||||
Date: Sat, 12 Mar 2016 18:44:19 +0100
 | 
			
		||||
Subject: [PATCH] net: mvneta: fix error messages in mvneta_port_down function
 | 
			
		||||
 | 
			
		||||
This commit corrects error printing when shutting down the port.
 | 
			
		||||
 | 
			
		||||
[gregory.clement@free-electrons.com: split initial commit in two
 | 
			
		||||
individual changes]
 | 
			
		||||
Signed-off-by: Dmitri Epshtein <dima@marvell.com>
 | 
			
		||||
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
 | 
			
		||||
Signed-off-by: David S. Miller <davem@davemloft.net>
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
+++ b/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
@@ -1105,7 +1105,7 @@ static void mvneta_port_down(struct mvne
 | 
			
		||||
 	do {
 | 
			
		||||
 		if (count++ >= MVNETA_RX_DISABLE_TIMEOUT_MSEC) {
 | 
			
		||||
 			netdev_warn(pp->dev,
 | 
			
		||||
-				    "TIMEOUT for RX stopped ! rx_queue_cmd: 0x08%x\n",
 | 
			
		||||
+				    "TIMEOUT for RX stopped ! rx_queue_cmd: 0x%08x\n",
 | 
			
		||||
 				    val);
 | 
			
		||||
 			break;
 | 
			
		||||
 		}
 | 
			
		||||
@@ -1144,7 +1144,7 @@ static void mvneta_port_down(struct mvne
 | 
			
		||||
 	do {
 | 
			
		||||
 		if (count++ >= MVNETA_TX_FIFO_EMPTY_TIMEOUT) {
 | 
			
		||||
 			netdev_warn(pp->dev,
 | 
			
		||||
-				    "TX FIFO empty timeout status=0x08%x\n",
 | 
			
		||||
+				    "TX FIFO empty timeout status=0x%08x\n",
 | 
			
		||||
 				    val);
 | 
			
		||||
 			break;
 | 
			
		||||
 		}
 | 
			
		||||
@@ -0,0 +1,56 @@
 | 
			
		||||
From: Jisheng Zhang <jszhang@marvell.com>
 | 
			
		||||
Date: Wed, 30 Mar 2016 19:55:21 +0800
 | 
			
		||||
Subject: [PATCH] net: mvneta: replace MVNETA_CPU_D_CACHE_LINE_SIZE with
 | 
			
		||||
 L1_CACHE_BYTES
 | 
			
		||||
 | 
			
		||||
The mvneta is also used in some Marvell berlin family SoCs which may
 | 
			
		||||
have 64bytes cacheline size. Replace the MVNETA_CPU_D_CACHE_LINE_SIZE
 | 
			
		||||
usage with L1_CACHE_BYTES.
 | 
			
		||||
 | 
			
		||||
And since dma_alloc_coherent() is always cacheline size aligned, so
 | 
			
		||||
remove the align checks.
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Jisheng Zhang <jszhang@marvell.com>
 | 
			
		||||
Signed-off-by: David S. Miller <davem@davemloft.net>
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
+++ b/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
@@ -260,7 +260,6 @@
 | 
			
		||||
 
 | 
			
		||||
 #define MVNETA_VLAN_TAG_LEN             4
 | 
			
		||||
 
 | 
			
		||||
-#define MVNETA_CPU_D_CACHE_LINE_SIZE    32
 | 
			
		||||
 #define MVNETA_TX_CSUM_DEF_SIZE		1600
 | 
			
		||||
 #define MVNETA_TX_CSUM_MAX_SIZE		9800
 | 
			
		||||
 #define MVNETA_ACC_MODE_EXT1		1
 | 
			
		||||
@@ -300,7 +299,7 @@
 | 
			
		||||
 #define MVNETA_RX_PKT_SIZE(mtu) \
 | 
			
		||||
 	ALIGN((mtu) + MVNETA_MH_SIZE + MVNETA_VLAN_TAG_LEN + \
 | 
			
		||||
 	      ETH_HLEN + ETH_FCS_LEN,			     \
 | 
			
		||||
-	      MVNETA_CPU_D_CACHE_LINE_SIZE)
 | 
			
		||||
+	      L1_CACHE_BYTES)
 | 
			
		||||
 
 | 
			
		||||
 #define IS_TSO_HEADER(txq, addr) \
 | 
			
		||||
 	((addr >= txq->tso_hdrs_phys) && \
 | 
			
		||||
@@ -2762,9 +2761,6 @@ static int mvneta_rxq_init(struct mvneta
 | 
			
		||||
 	if (rxq->descs == NULL)
 | 
			
		||||
 		return -ENOMEM;
 | 
			
		||||
 
 | 
			
		||||
-	BUG_ON(rxq->descs !=
 | 
			
		||||
-	       PTR_ALIGN(rxq->descs, MVNETA_CPU_D_CACHE_LINE_SIZE));
 | 
			
		||||
-
 | 
			
		||||
 	rxq->last_desc = rxq->size - 1;
 | 
			
		||||
 
 | 
			
		||||
 	/* Set Rx descriptors queue starting address */
 | 
			
		||||
@@ -2835,10 +2831,6 @@ static int mvneta_txq_init(struct mvneta
 | 
			
		||||
 	if (txq->descs == NULL)
 | 
			
		||||
 		return -ENOMEM;
 | 
			
		||||
 
 | 
			
		||||
-	/* Make sure descriptor address is cache line size aligned  */
 | 
			
		||||
-	BUG_ON(txq->descs !=
 | 
			
		||||
-	       PTR_ALIGN(txq->descs, MVNETA_CPU_D_CACHE_LINE_SIZE));
 | 
			
		||||
-
 | 
			
		||||
 	txq->last_desc = txq->size - 1;
 | 
			
		||||
 
 | 
			
		||||
 	/* Set maximum bandwidth for enabled TXQs */
 | 
			
		||||
@@ -0,0 +1,75 @@
 | 
			
		||||
From: Marcin Wojtas <mw@semihalf.com>
 | 
			
		||||
Date: Fri, 1 Apr 2016 15:21:18 +0200
 | 
			
		||||
Subject: [PATCH] net: mvneta: fix changing MTU when using per-cpu processing
 | 
			
		||||
 | 
			
		||||
After enabling per-cpu processing it appeared that under heavy load
 | 
			
		||||
changing MTU can result in blocking all port's interrupts and
 | 
			
		||||
transmitting data is not possible after the change.
 | 
			
		||||
 | 
			
		||||
This commit fixes above issue by disabling percpu interrupts for the
 | 
			
		||||
time, when TXQs and RXQs are reconfigured.
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
 | 
			
		||||
Signed-off-by: David S. Miller <davem@davemloft.net>
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
+++ b/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
@@ -3040,6 +3040,20 @@ static int mvneta_check_mtu_valid(struct
 | 
			
		||||
 	return mtu;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
+static void mvneta_percpu_enable(void *arg)
 | 
			
		||||
+{
 | 
			
		||||
+	struct mvneta_port *pp = arg;
 | 
			
		||||
+
 | 
			
		||||
+	enable_percpu_irq(pp->dev->irq, IRQ_TYPE_NONE);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static void mvneta_percpu_disable(void *arg)
 | 
			
		||||
+{
 | 
			
		||||
+	struct mvneta_port *pp = arg;
 | 
			
		||||
+
 | 
			
		||||
+	disable_percpu_irq(pp->dev->irq);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
 /* Change the device mtu */
 | 
			
		||||
 static int mvneta_change_mtu(struct net_device *dev, int mtu)
 | 
			
		||||
 {
 | 
			
		||||
@@ -3064,6 +3078,7 @@ static int mvneta_change_mtu(struct net_
 | 
			
		||||
 	 * reallocation of the queues
 | 
			
		||||
 	 */
 | 
			
		||||
 	mvneta_stop_dev(pp);
 | 
			
		||||
+	on_each_cpu(mvneta_percpu_disable, pp, true);
 | 
			
		||||
 
 | 
			
		||||
 	mvneta_cleanup_txqs(pp);
 | 
			
		||||
 	mvneta_cleanup_rxqs(pp);
 | 
			
		||||
@@ -3087,6 +3102,7 @@ static int mvneta_change_mtu(struct net_
 | 
			
		||||
 		return ret;
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
+	on_each_cpu(mvneta_percpu_enable, pp, true);
 | 
			
		||||
 	mvneta_start_dev(pp);
 | 
			
		||||
 	mvneta_port_up(pp);
 | 
			
		||||
 
 | 
			
		||||
@@ -3240,20 +3256,6 @@ static void mvneta_mdio_remove(struct mv
 | 
			
		||||
 	pp->phy_dev = NULL;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
-static void mvneta_percpu_enable(void *arg)
 | 
			
		||||
-{
 | 
			
		||||
-	struct mvneta_port *pp = arg;
 | 
			
		||||
-
 | 
			
		||||
-	enable_percpu_irq(pp->dev->irq, IRQ_TYPE_NONE);
 | 
			
		||||
-}
 | 
			
		||||
-
 | 
			
		||||
-static void mvneta_percpu_disable(void *arg)
 | 
			
		||||
-{
 | 
			
		||||
-	struct mvneta_port *pp = arg;
 | 
			
		||||
-
 | 
			
		||||
-	disable_percpu_irq(pp->dev->irq);
 | 
			
		||||
-}
 | 
			
		||||
-
 | 
			
		||||
 /* Electing a CPU must be done in an atomic way: it should be done
 | 
			
		||||
  * after or before the removal/insertion of a CPU and this function is
 | 
			
		||||
  * not reentrant.
 | 
			
		||||
@@ -0,0 +1,53 @@
 | 
			
		||||
From: Marcin Wojtas <mw@semihalf.com>
 | 
			
		||||
Date: Mon, 14 Mar 2016 09:38:57 +0100
 | 
			
		||||
Subject: [PATCH] ARM: dts: armada-38x: add buffer manager nodes
 | 
			
		||||
 | 
			
		||||
Armada 38x network controller supports hardware buffer management (BM).
 | 
			
		||||
Since it is now enabled in mvneta driver, appropriate nodes can be added
 | 
			
		||||
to armada-38x.dtsi - for the actual common BM unit (bm@c8000) and its
 | 
			
		||||
internal SRAM (bm-bppi), which is used for indirect access to buffer
 | 
			
		||||
pointer ring residing in DRAM.
 | 
			
		||||
 | 
			
		||||
Pools - ports mapping, bm-bppi entry in 'soc' node's ranges and optional
 | 
			
		||||
parameters are supposed to be set in board files.
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
 | 
			
		||||
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
 | 
			
		||||
Signed-off-by: David S. Miller <davem@davemloft.net>
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
--- a/arch/arm/boot/dts/armada-38x.dtsi
 | 
			
		||||
+++ b/arch/arm/boot/dts/armada-38x.dtsi
 | 
			
		||||
@@ -540,6 +540,14 @@
 | 
			
		||||
 				status = "disabled";
 | 
			
		||||
 			};
 | 
			
		||||
 
 | 
			
		||||
+			bm: bm@c8000 {
 | 
			
		||||
+				compatible = "marvell,armada-380-neta-bm";
 | 
			
		||||
+				reg = <0xc8000 0xac>;
 | 
			
		||||
+				clocks = <&gateclk 13>;
 | 
			
		||||
+				internal-mem = <&bm_bppi>;
 | 
			
		||||
+				status = "disabled";
 | 
			
		||||
+			};
 | 
			
		||||
+
 | 
			
		||||
 			sata@e0000 {
 | 
			
		||||
 				compatible = "marvell,armada-380-ahci";
 | 
			
		||||
 				reg = <0xe0000 0x2000>;
 | 
			
		||||
@@ -618,6 +626,17 @@
 | 
			
		||||
 			#size-cells = <1>;
 | 
			
		||||
 			ranges = <0 MBUS_ID(0x09, 0x15) 0 0x800>;
 | 
			
		||||
 		};
 | 
			
		||||
+
 | 
			
		||||
+		bm_bppi: bm-bppi {
 | 
			
		||||
+			compatible = "mmio-sram";
 | 
			
		||||
+			reg = <MBUS_ID(0x0c, 0x04) 0 0x100000>;
 | 
			
		||||
+			ranges = <0 MBUS_ID(0x0c, 0x04) 0 0x100000>;
 | 
			
		||||
+			#address-cells = <1>;
 | 
			
		||||
+			#size-cells = <1>;
 | 
			
		||||
+			clocks = <&gateclk 13>;
 | 
			
		||||
+			no-memory-wc;
 | 
			
		||||
+			status = "disabled";
 | 
			
		||||
+		};
 | 
			
		||||
 	};
 | 
			
		||||
 
 | 
			
		||||
 	clocks {
 | 
			
		||||
@@ -0,0 +1,53 @@
 | 
			
		||||
From: Marcin Wojtas <mw@semihalf.com>
 | 
			
		||||
Date: Mon, 14 Mar 2016 09:38:59 +0100
 | 
			
		||||
Subject: [PATCH] ARM: dts: armada-xp: add buffer manager nodes
 | 
			
		||||
 | 
			
		||||
Armada XP network controller supports hardware buffer management (BM).
 | 
			
		||||
Since it is now enabled in mvneta driver, appropriate nodes can be added
 | 
			
		||||
to armada-xp.dtsi - for the actual common BM unit (bm@c0000) and its
 | 
			
		||||
internal SRAM (bm-bppi), which is used for indirect access to buffer
 | 
			
		||||
pointer ring residing in DRAM.
 | 
			
		||||
 | 
			
		||||
Pools - ports mapping, bm-bppi entry in 'soc' node's ranges and optional
 | 
			
		||||
parameters are supposed to be set in board files.
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
 | 
			
		||||
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
 | 
			
		||||
Signed-off-by: David S. Miller <davem@davemloft.net>
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
--- a/arch/arm/boot/dts/armada-xp.dtsi
 | 
			
		||||
+++ b/arch/arm/boot/dts/armada-xp.dtsi
 | 
			
		||||
@@ -253,6 +253,14 @@
 | 
			
		||||
 				marvell,crypto-sram-size = <0x800>;
 | 
			
		||||
 			};
 | 
			
		||||
 
 | 
			
		||||
+			bm: bm@c0000 {
 | 
			
		||||
+				compatible = "marvell,armada-380-neta-bm";
 | 
			
		||||
+				reg = <0xc0000 0xac>;
 | 
			
		||||
+				clocks = <&gateclk 13>;
 | 
			
		||||
+				internal-mem = <&bm_bppi>;
 | 
			
		||||
+				status = "disabled";
 | 
			
		||||
+			};
 | 
			
		||||
+
 | 
			
		||||
 			xor@f0900 {
 | 
			
		||||
 				compatible = "marvell,orion-xor";
 | 
			
		||||
 				reg = <0xF0900 0x100
 | 
			
		||||
@@ -291,6 +299,17 @@
 | 
			
		||||
 			#size-cells = <1>;
 | 
			
		||||
 			ranges = <0 MBUS_ID(0x09, 0x05) 0 0x800>;
 | 
			
		||||
 		};
 | 
			
		||||
+
 | 
			
		||||
+		bm_bppi: bm-bppi {
 | 
			
		||||
+			compatible = "mmio-sram";
 | 
			
		||||
+			reg = <MBUS_ID(0x0c, 0x04) 0 0x100000>;
 | 
			
		||||
+			ranges = <0 MBUS_ID(0x0c, 0x04) 0 0x100000>;
 | 
			
		||||
+			#address-cells = <1>;
 | 
			
		||||
+			#size-cells = <1>;
 | 
			
		||||
+			clocks = <&gateclk 13>;
 | 
			
		||||
+			no-memory-wc;
 | 
			
		||||
+			status = "disabled";
 | 
			
		||||
+		};
 | 
			
		||||
 	};
 | 
			
		||||
 
 | 
			
		||||
 	clocks {
 | 
			
		||||
@@ -0,0 +1,611 @@
 | 
			
		||||
From 4c945e8556ec7ea5b19d4f8721b212f468656e0d Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
Date: Sun, 6 Dec 2015 21:52:06 +0000
 | 
			
		||||
Subject: [PATCH] ARM: dts: Add SolidRun Armada 388 Clearfog A1 DT file
 | 
			
		||||
 | 
			
		||||
Add support for the SolidRun Armada 388 Clearfog A1 board.  This board
 | 
			
		||||
has an Armada 388 microsom, dedicated gigabit ethernet, six switched
 | 
			
		||||
gigabit ethernet ports, SFP cage, two Mini-PCIe/mSATA slots, a m.2 SATA
 | 
			
		||||
slot, and a MikroBUS connector to allow MikroBUS modules to be added.
 | 
			
		||||
 | 
			
		||||
This DT file adds support for all board facilities with the exception
 | 
			
		||||
of full SFP support.
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
Acked-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
 | 
			
		||||
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
 | 
			
		||||
---
 | 
			
		||||
 arch/arm/boot/dts/Makefile                         |   1 +
 | 
			
		||||
 arch/arm/boot/dts/armada-388-clearfog.dts          | 456 +++++++++++++++++++++
 | 
			
		||||
 .../arm/boot/dts/armada-38x-solidrun-microsom.dtsi | 115 ++++++
 | 
			
		||||
 3 files changed, 572 insertions(+)
 | 
			
		||||
 create mode 100644 arch/arm/boot/dts/armada-388-clearfog.dts
 | 
			
		||||
 create mode 100644 arch/arm/boot/dts/armada-38x-solidrun-microsom.dtsi
 | 
			
		||||
 | 
			
		||||
--- a/arch/arm/boot/dts/Makefile
 | 
			
		||||
+++ b/arch/arm/boot/dts/Makefile
 | 
			
		||||
@@ -750,6 +750,7 @@ dtb-$(CONFIG_MACH_ARMADA_38X) += \
 | 
			
		||||
 	armada-385-linksys-cobra.dtb \
 | 
			
		||||
 	armada-385-linksys-rango.dtb \
 | 
			
		||||
 	armada-385-linksys-shelby.dtb \
 | 
			
		||||
+	armada-388-clearfog.dtb \
 | 
			
		||||
 	armada-388-db.dtb \
 | 
			
		||||
 	armada-388-gp.dtb \
 | 
			
		||||
 	armada-388-rd.dtb
 | 
			
		||||
--- /dev/null
 | 
			
		||||
+++ b/arch/arm/boot/dts/armada-388-clearfog.dts
 | 
			
		||||
@@ -0,0 +1,456 @@
 | 
			
		||||
+/*
 | 
			
		||||
+ * Device Tree file for SolidRun Clearfog revision A1 rev 2.0 (88F6828)
 | 
			
		||||
+ *
 | 
			
		||||
+ *  Copyright (C) 2015 Russell King
 | 
			
		||||
+ *
 | 
			
		||||
+ * This board is in development; the contents of this file work with
 | 
			
		||||
+ * the A1 rev 2.0 of the board, which does not represent final
 | 
			
		||||
+ * production board.  Things will change, don't expect this file to
 | 
			
		||||
+ * remain compatible info the future.
 | 
			
		||||
+ *
 | 
			
		||||
+ * This file is dual-licensed: you can use it either under the terms
 | 
			
		||||
+ * of the GPL or the X11 license, at your option. Note that this dual
 | 
			
		||||
+ * licensing only applies to this file, and not this project as a
 | 
			
		||||
+ * whole.
 | 
			
		||||
+ *
 | 
			
		||||
+ *  a) This file 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.
 | 
			
		||||
+ *
 | 
			
		||||
+ *     This file 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.
 | 
			
		||||
+ *
 | 
			
		||||
+ * Or, alternatively
 | 
			
		||||
+ *
 | 
			
		||||
+ *  b) Permission is hereby granted, free of charge, to any person
 | 
			
		||||
+ *     obtaining a copy of this software and associated documentation
 | 
			
		||||
+ *     files (the "Software"), to deal in the Software without
 | 
			
		||||
+ *     restriction, including without limitation the rights to use
 | 
			
		||||
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
 | 
			
		||||
+ *     sell copies of the Software, and to permit persons to whom the
 | 
			
		||||
+ *     Software is furnished to do so, subject to the following
 | 
			
		||||
+ *     conditions:
 | 
			
		||||
+ *
 | 
			
		||||
+ *     The above copyright notice and this permission notice shall be
 | 
			
		||||
+ *     included in all copies or substantial portions of the Software.
 | 
			
		||||
+ *
 | 
			
		||||
+ *     THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND
 | 
			
		||||
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 | 
			
		||||
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 | 
			
		||||
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 | 
			
		||||
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
 | 
			
		||||
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 | 
			
		||||
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 | 
			
		||||
+ *     OTHER DEALINGS IN THE SOFTWARE.
 | 
			
		||||
+ */
 | 
			
		||||
+
 | 
			
		||||
+/dts-v1/;
 | 
			
		||||
+#include "armada-388.dtsi"
 | 
			
		||||
+#include "armada-38x-solidrun-microsom.dtsi"
 | 
			
		||||
+
 | 
			
		||||
+/ {
 | 
			
		||||
+	model = "SolidRun Clearfog A1";
 | 
			
		||||
+	compatible = "solidrun,clearfog-a1", "marvell,armada388",
 | 
			
		||||
+		"marvell,armada385", "marvell,armada380";
 | 
			
		||||
+
 | 
			
		||||
+	aliases {
 | 
			
		||||
+		/* So that mvebu u-boot can update the MAC addresses */
 | 
			
		||||
+		ethernet1 = ð0;
 | 
			
		||||
+		ethernet2 = ð1;
 | 
			
		||||
+		ethernet3 = ð2;
 | 
			
		||||
+	};
 | 
			
		||||
+
 | 
			
		||||
+	chosen {
 | 
			
		||||
+		stdout-path = "serial0:115200n8";
 | 
			
		||||
+	};
 | 
			
		||||
+
 | 
			
		||||
+	reg_3p3v: regulator-3p3v {
 | 
			
		||||
+		compatible = "regulator-fixed";
 | 
			
		||||
+		regulator-name = "3P3V";
 | 
			
		||||
+		regulator-min-microvolt = <3300000>;
 | 
			
		||||
+		regulator-max-microvolt = <3300000>;
 | 
			
		||||
+		regulator-always-on;
 | 
			
		||||
+	};
 | 
			
		||||
+
 | 
			
		||||
+	soc {
 | 
			
		||||
+		internal-regs {
 | 
			
		||||
+			ethernet@30000 {
 | 
			
		||||
+				phy-mode = "sgmii";
 | 
			
		||||
+				status = "okay";
 | 
			
		||||
+
 | 
			
		||||
+				fixed-link {
 | 
			
		||||
+					speed = <1000>;
 | 
			
		||||
+					full-duplex;
 | 
			
		||||
+				};
 | 
			
		||||
+			};
 | 
			
		||||
+
 | 
			
		||||
+			ethernet@34000 {
 | 
			
		||||
+				phy-mode = "sgmii";
 | 
			
		||||
+				status = "okay";
 | 
			
		||||
+
 | 
			
		||||
+				fixed-link {
 | 
			
		||||
+					speed = <1000>;
 | 
			
		||||
+					full-duplex;
 | 
			
		||||
+				};
 | 
			
		||||
+			};
 | 
			
		||||
+
 | 
			
		||||
+			i2c@11000 {
 | 
			
		||||
+				/* Is there anything on this? */
 | 
			
		||||
+				clock-frequency = <100000>;
 | 
			
		||||
+				pinctrl-0 = <&i2c0_pins>;
 | 
			
		||||
+				pinctrl-names = "default";
 | 
			
		||||
+				status = "okay";
 | 
			
		||||
+
 | 
			
		||||
+				/*
 | 
			
		||||
+				 * PCA9655 GPIO expander, up to 1MHz clock.
 | 
			
		||||
+				 *  0-CON3 CLKREQ#
 | 
			
		||||
+				 *  1-CON3 PERST#
 | 
			
		||||
+				 *  2-CON2 PERST#
 | 
			
		||||
+				 *  3-CON3 W_DISABLE
 | 
			
		||||
+				 *  4-CON2 CLKREQ#
 | 
			
		||||
+				 *  5-USB3 overcurrent
 | 
			
		||||
+				 *  6-USB3 power
 | 
			
		||||
+				 *  7-CON2 W_DISABLE
 | 
			
		||||
+				 *  8-JP4 P1
 | 
			
		||||
+				 *  9-JP4 P4
 | 
			
		||||
+				 * 10-JP4 P5
 | 
			
		||||
+				 * 11-m.2 DEVSLP
 | 
			
		||||
+				 * 12-SFP_LOS
 | 
			
		||||
+				 * 13-SFP_TX_FAULT
 | 
			
		||||
+				 * 14-SFP_TX_DISABLE
 | 
			
		||||
+				 * 15-SFP_MOD_DEF0
 | 
			
		||||
+				 */
 | 
			
		||||
+				expander0: gpio-expander@20 {
 | 
			
		||||
+					/*
 | 
			
		||||
+					 * This is how it should be:
 | 
			
		||||
+					 * compatible = "onnn,pca9655",
 | 
			
		||||
+					 *	 "nxp,pca9555";
 | 
			
		||||
+					 * but you can't do this because of
 | 
			
		||||
+					 * the way I2C works.
 | 
			
		||||
+					 */
 | 
			
		||||
+					compatible = "nxp,pca9555";
 | 
			
		||||
+					gpio-controller;
 | 
			
		||||
+					#gpio-cells = <2>;
 | 
			
		||||
+					reg = <0x20>;
 | 
			
		||||
+
 | 
			
		||||
+					pcie1_0_clkreq {
 | 
			
		||||
+						gpio-hog;
 | 
			
		||||
+						gpios = <0 GPIO_ACTIVE_LOW>;
 | 
			
		||||
+						input;
 | 
			
		||||
+						line-name = "pcie1.0-clkreq";
 | 
			
		||||
+					};
 | 
			
		||||
+					pcie1_0_w_disable {
 | 
			
		||||
+						gpio-hog;
 | 
			
		||||
+						gpios = <3 GPIO_ACTIVE_LOW>;
 | 
			
		||||
+						output-low;
 | 
			
		||||
+						line-name = "pcie1.0-w-disable";
 | 
			
		||||
+					};
 | 
			
		||||
+					pcie2_0_clkreq {
 | 
			
		||||
+						gpio-hog;
 | 
			
		||||
+						gpios = <4 GPIO_ACTIVE_LOW>;
 | 
			
		||||
+						input;
 | 
			
		||||
+						line-name = "pcie2.0-clkreq";
 | 
			
		||||
+					};
 | 
			
		||||
+					pcie2_0_w_disable {
 | 
			
		||||
+						gpio-hog;
 | 
			
		||||
+						gpios = <7 GPIO_ACTIVE_LOW>;
 | 
			
		||||
+						output-low;
 | 
			
		||||
+						line-name = "pcie2.0-w-disable";
 | 
			
		||||
+					};
 | 
			
		||||
+					usb3_ilimit {
 | 
			
		||||
+						gpio-hog;
 | 
			
		||||
+						gpios = <5 GPIO_ACTIVE_LOW>;
 | 
			
		||||
+						input;
 | 
			
		||||
+						line-name = "usb3-current-limit";
 | 
			
		||||
+					};
 | 
			
		||||
+					usb3_power {
 | 
			
		||||
+						gpio-hog;
 | 
			
		||||
+						gpios = <6 GPIO_ACTIVE_HIGH>;
 | 
			
		||||
+						output-high;
 | 
			
		||||
+						line-name = "usb3-power";
 | 
			
		||||
+					};
 | 
			
		||||
+					m2_devslp {
 | 
			
		||||
+						gpio-hog;
 | 
			
		||||
+						gpios = <11 GPIO_ACTIVE_HIGH>;
 | 
			
		||||
+						output-low;
 | 
			
		||||
+						line-name = "m.2 devslp";
 | 
			
		||||
+					};
 | 
			
		||||
+					sfp_los {
 | 
			
		||||
+						/* SFP loss of signal */
 | 
			
		||||
+						gpio-hog;
 | 
			
		||||
+						gpios = <12 GPIO_ACTIVE_HIGH>;
 | 
			
		||||
+						input;
 | 
			
		||||
+						line-name = "sfp-los";
 | 
			
		||||
+					};
 | 
			
		||||
+					sfp_tx_fault {
 | 
			
		||||
+						/* SFP laser fault */
 | 
			
		||||
+						gpio-hog;
 | 
			
		||||
+						gpios = <13 GPIO_ACTIVE_HIGH>;
 | 
			
		||||
+						input;
 | 
			
		||||
+						line-name = "sfp-tx-fault";
 | 
			
		||||
+					};
 | 
			
		||||
+					sfp_tx_disable {
 | 
			
		||||
+						/* SFP transmit disable */
 | 
			
		||||
+						gpio-hog;
 | 
			
		||||
+						gpios = <14 GPIO_ACTIVE_HIGH>;
 | 
			
		||||
+						output-low;
 | 
			
		||||
+						line-name = "sfp-tx-disable";
 | 
			
		||||
+					};
 | 
			
		||||
+					sfp_mod_def0 {
 | 
			
		||||
+						/* SFP module present */
 | 
			
		||||
+						gpio-hog;
 | 
			
		||||
+						gpios = <15 GPIO_ACTIVE_LOW>;
 | 
			
		||||
+						input;
 | 
			
		||||
+						line-name = "sfp-mod-def0";
 | 
			
		||||
+					};
 | 
			
		||||
+				};
 | 
			
		||||
+
 | 
			
		||||
+				/* The MCP3021 is 100kHz clock only */
 | 
			
		||||
+				mikrobus_adc: mcp3021@4c {
 | 
			
		||||
+					compatible = "microchip,mcp3021";
 | 
			
		||||
+					reg = <0x4c>;
 | 
			
		||||
+				};
 | 
			
		||||
+
 | 
			
		||||
+				/* Also something at 0x64 */
 | 
			
		||||
+			};
 | 
			
		||||
+
 | 
			
		||||
+			i2c@11100 {
 | 
			
		||||
+				/*
 | 
			
		||||
+				 * Routed to SFP, mikrobus, and PCIe.
 | 
			
		||||
+				 * SFP limits this to 100kHz, and requires
 | 
			
		||||
+				 *  an AT24C01A/02/04 with address pins tied
 | 
			
		||||
+				 *  low, which takes addresses 0x50 and 0x51.
 | 
			
		||||
+				 * Mikrobus doesn't specify beyond an I2C
 | 
			
		||||
+				 *  bus being present.
 | 
			
		||||
+				 * PCIe uses ARP to assign addresses, or
 | 
			
		||||
+				 *  0x63-0x64.
 | 
			
		||||
+				 */
 | 
			
		||||
+				clock-frequency = <100000>;
 | 
			
		||||
+				pinctrl-0 = <&clearfog_i2c1_pins>;
 | 
			
		||||
+				pinctrl-names = "default";
 | 
			
		||||
+				status = "okay";
 | 
			
		||||
+			};
 | 
			
		||||
+
 | 
			
		||||
+			mdio@72004 {
 | 
			
		||||
+				pinctrl-0 = <&mdio_pins>;
 | 
			
		||||
+				pinctrl-names = "default";
 | 
			
		||||
+
 | 
			
		||||
+				phy_dedicated: ethernet-phy@0 {
 | 
			
		||||
+					/*
 | 
			
		||||
+					 * Annoyingly, the marvell phy driver
 | 
			
		||||
+					 * configures the LED register, rather
 | 
			
		||||
+					 * than preserving reset-loaded setting.
 | 
			
		||||
+					 * We undo that rubbish here.
 | 
			
		||||
+					 */
 | 
			
		||||
+					marvell,reg-init = <3 16 0 0x101e>;
 | 
			
		||||
+					reg = <0>;
 | 
			
		||||
+				};
 | 
			
		||||
+			};
 | 
			
		||||
+
 | 
			
		||||
+			pinctrl@18000 {
 | 
			
		||||
+				clearfog_dsa0_clk_pins: clearfog-dsa0-clk-pins {
 | 
			
		||||
+					marvell,pins = "mpp46";
 | 
			
		||||
+					marvell,function = "ref";
 | 
			
		||||
+				};
 | 
			
		||||
+				clearfog_dsa0_pins: clearfog-dsa0-pins {
 | 
			
		||||
+					marvell,pins = "mpp23", "mpp41";
 | 
			
		||||
+					marvell,function = "gpio";
 | 
			
		||||
+				};
 | 
			
		||||
+				clearfog_i2c1_pins: i2c1-pins {
 | 
			
		||||
+					/* SFP, PCIe, mSATA, mikrobus */
 | 
			
		||||
+					marvell,pins = "mpp26", "mpp27";
 | 
			
		||||
+					marvell,function = "i2c1";
 | 
			
		||||
+				};
 | 
			
		||||
+				clearfog_sdhci_cd_pins: clearfog-sdhci-cd-pins {
 | 
			
		||||
+					marvell,pins = "mpp20";
 | 
			
		||||
+					marvell,function = "gpio";
 | 
			
		||||
+				};
 | 
			
		||||
+				clearfog_sdhci_pins: clearfog-sdhci-pins {
 | 
			
		||||
+					marvell,pins = "mpp21", "mpp28",
 | 
			
		||||
+						       "mpp37", "mpp38",
 | 
			
		||||
+						       "mpp39", "mpp40";
 | 
			
		||||
+					marvell,function = "sd0";
 | 
			
		||||
+				};
 | 
			
		||||
+				clearfog_spi1_cs_pins: spi1-cs-pins {
 | 
			
		||||
+					marvell,pins = "mpp55";
 | 
			
		||||
+					marvell,function = "spi1";
 | 
			
		||||
+				};
 | 
			
		||||
+				mikro_pins: mikro-pins {
 | 
			
		||||
+					/* int: mpp22 rst: mpp29 */
 | 
			
		||||
+					marvell,pins = "mpp22", "mpp29";
 | 
			
		||||
+					marvell,function = "gpio";
 | 
			
		||||
+				};
 | 
			
		||||
+				mikro_spi_pins: mikro-spi-pins {
 | 
			
		||||
+					marvell,pins = "mpp43";
 | 
			
		||||
+					marvell,function = "spi1";
 | 
			
		||||
+				};
 | 
			
		||||
+				mikro_uart_pins: mikro-uart-pins {
 | 
			
		||||
+					marvell,pins = "mpp24", "mpp25";
 | 
			
		||||
+					marvell,function = "ua1";
 | 
			
		||||
+				};
 | 
			
		||||
+				rear_button_pins: rear-button-pins {
 | 
			
		||||
+					marvell,pins = "mpp34";
 | 
			
		||||
+					marvell,function = "gpio";
 | 
			
		||||
+				};
 | 
			
		||||
+			};
 | 
			
		||||
+
 | 
			
		||||
+			sata@a8000 {
 | 
			
		||||
+				/* pinctrl? */
 | 
			
		||||
+				status = "okay";
 | 
			
		||||
+			};
 | 
			
		||||
+
 | 
			
		||||
+			sata@e0000 {
 | 
			
		||||
+				/* pinctrl? */
 | 
			
		||||
+				status = "okay";
 | 
			
		||||
+			};
 | 
			
		||||
+
 | 
			
		||||
+			sdhci@d8000 {
 | 
			
		||||
+				bus-width = <4>;
 | 
			
		||||
+				cd-gpios = <&gpio0 20 GPIO_ACTIVE_LOW>;
 | 
			
		||||
+				no-1-8-v;
 | 
			
		||||
+				pinctrl-0 = <&clearfog_sdhci_pins
 | 
			
		||||
+					     &clearfog_sdhci_cd_pins>;
 | 
			
		||||
+				pinctrl-names = "default";
 | 
			
		||||
+				status = "okay";
 | 
			
		||||
+				vmmc = <®_3p3v>;
 | 
			
		||||
+				wp-inverted;
 | 
			
		||||
+			};
 | 
			
		||||
+
 | 
			
		||||
+			serial@12100 {
 | 
			
		||||
+				/* mikrobus uart */
 | 
			
		||||
+				pinctrl-0 = <&mikro_uart_pins>;
 | 
			
		||||
+				pinctrl-names = "default";
 | 
			
		||||
+				status = "okay";
 | 
			
		||||
+			};
 | 
			
		||||
+
 | 
			
		||||
+			spi@10680 {
 | 
			
		||||
+				/*
 | 
			
		||||
+				 * We don't seem to have the W25Q32 on the
 | 
			
		||||
+				 * A1 Rev 2.0 boards, so disable SPI.
 | 
			
		||||
+				 * CS0: W25Q32 (doesn't appear to be present)
 | 
			
		||||
+				 * CS1:
 | 
			
		||||
+				 * CS2: mikrobus
 | 
			
		||||
+				 */
 | 
			
		||||
+				pinctrl-0 = <&spi1_pins
 | 
			
		||||
+					     &clearfog_spi1_cs_pins
 | 
			
		||||
+					     &mikro_spi_pins>;
 | 
			
		||||
+				pinctrl-names = "default";
 | 
			
		||||
+				status = "okay";
 | 
			
		||||
+
 | 
			
		||||
+				spi-flash@0 {
 | 
			
		||||
+					#address-cells = <1>;
 | 
			
		||||
+					#size-cells = <0>;
 | 
			
		||||
+					compatible = "w25q32", "jedec,spi-nor";
 | 
			
		||||
+					reg = <0>; /* Chip select 0 */
 | 
			
		||||
+					spi-max-frequency = <3000000>;
 | 
			
		||||
+					status = "disabled";
 | 
			
		||||
+				};
 | 
			
		||||
+			};
 | 
			
		||||
+
 | 
			
		||||
+			usb@58000 {
 | 
			
		||||
+				/* CON3, nearest  power. */
 | 
			
		||||
+				status = "okay";
 | 
			
		||||
+			};
 | 
			
		||||
+
 | 
			
		||||
+			usb3@f0000 {
 | 
			
		||||
+				/* CON2, nearest CPU, USB2 only. */
 | 
			
		||||
+				status = "okay";
 | 
			
		||||
+			};
 | 
			
		||||
+
 | 
			
		||||
+			usb3@f8000 {
 | 
			
		||||
+				/* CON7 */
 | 
			
		||||
+				status = "okay";
 | 
			
		||||
+			};
 | 
			
		||||
+		};
 | 
			
		||||
+
 | 
			
		||||
+		pcie-controller {
 | 
			
		||||
+			status = "okay";
 | 
			
		||||
+			/*
 | 
			
		||||
+			 * The two PCIe units are accessible through
 | 
			
		||||
+			 * the mini-PCIe connectors on the board.
 | 
			
		||||
+			 */
 | 
			
		||||
+			pcie@2,0 {
 | 
			
		||||
+				/* Port 1, Lane 0. CON3, nearest power. */
 | 
			
		||||
+				reset-gpios = <&expander0 1 GPIO_ACTIVE_LOW>;
 | 
			
		||||
+				status = "okay";
 | 
			
		||||
+			};
 | 
			
		||||
+			pcie@3,0 {
 | 
			
		||||
+				/* Port 2, Lane 0. CON2, nearest CPU. */
 | 
			
		||||
+				reset-gpios = <&expander0 2 GPIO_ACTIVE_LOW>;
 | 
			
		||||
+				status = "okay";
 | 
			
		||||
+			};
 | 
			
		||||
+		};
 | 
			
		||||
+	};
 | 
			
		||||
+
 | 
			
		||||
+	dsa@0 {
 | 
			
		||||
+		compatible = "marvell,dsa";
 | 
			
		||||
+		dsa,ethernet = <ð1>;
 | 
			
		||||
+		dsa,mii-bus = <&mdio>;
 | 
			
		||||
+		pinctrl-0 = <&clearfog_dsa0_clk_pins &clearfog_dsa0_pins>;
 | 
			
		||||
+		pinctrl-names = "default";
 | 
			
		||||
+		#address-cells = <2>;
 | 
			
		||||
+		#size-cells = <0>;
 | 
			
		||||
+
 | 
			
		||||
+		switch@0 {
 | 
			
		||||
+			#address-cells = <1>;
 | 
			
		||||
+			#size-cells = <0>;
 | 
			
		||||
+			reg = <4 0>;
 | 
			
		||||
+
 | 
			
		||||
+			port@0 {
 | 
			
		||||
+				reg = <0>;
 | 
			
		||||
+				label = "lan1";
 | 
			
		||||
+			};
 | 
			
		||||
+
 | 
			
		||||
+			port@1 {
 | 
			
		||||
+				reg = <1>;
 | 
			
		||||
+				label = "lan2";
 | 
			
		||||
+			};
 | 
			
		||||
+
 | 
			
		||||
+			port@2 {
 | 
			
		||||
+				reg = <2>;
 | 
			
		||||
+				label = "lan3";
 | 
			
		||||
+			};
 | 
			
		||||
+
 | 
			
		||||
+			port@3 {
 | 
			
		||||
+				reg = <3>;
 | 
			
		||||
+				label = "lan4";
 | 
			
		||||
+			};
 | 
			
		||||
+
 | 
			
		||||
+			port@4 {
 | 
			
		||||
+				reg = <4>;
 | 
			
		||||
+				label = "lan5";
 | 
			
		||||
+			};
 | 
			
		||||
+
 | 
			
		||||
+			port@5 {
 | 
			
		||||
+				reg = <5>;
 | 
			
		||||
+				label = "cpu";
 | 
			
		||||
+			};
 | 
			
		||||
+
 | 
			
		||||
+			port@6 {
 | 
			
		||||
+				/* 88E1512 external phy */
 | 
			
		||||
+				reg = <6>;
 | 
			
		||||
+				label = "lan6";
 | 
			
		||||
+				fixed-link {
 | 
			
		||||
+					speed = <1000>;
 | 
			
		||||
+					full-duplex;
 | 
			
		||||
+				};
 | 
			
		||||
+			};
 | 
			
		||||
+		};
 | 
			
		||||
+	};
 | 
			
		||||
+
 | 
			
		||||
+	gpio-keys {
 | 
			
		||||
+		compatible = "gpio-keys";
 | 
			
		||||
+		pinctrl-0 = <&rear_button_pins>;
 | 
			
		||||
+		pinctrl-names = "default";
 | 
			
		||||
+
 | 
			
		||||
+		button_0 {
 | 
			
		||||
+			/* The rear SW3 button */
 | 
			
		||||
+			label = "Rear Button";
 | 
			
		||||
+			gpios = <&gpio1 2 GPIO_ACTIVE_LOW>;
 | 
			
		||||
+			linux,can-disable;
 | 
			
		||||
+			linux,code = <BTN_0>;
 | 
			
		||||
+		};
 | 
			
		||||
+	};
 | 
			
		||||
+};
 | 
			
		||||
--- /dev/null
 | 
			
		||||
+++ b/arch/arm/boot/dts/armada-38x-solidrun-microsom.dtsi
 | 
			
		||||
@@ -0,0 +1,115 @@
 | 
			
		||||
+/*
 | 
			
		||||
+ * Device Tree file for SolidRun Armada 38x Microsom
 | 
			
		||||
+ *
 | 
			
		||||
+ *  Copyright (C) 2015 Russell King
 | 
			
		||||
+ *
 | 
			
		||||
+ * This board is in development; the contents of this file work with
 | 
			
		||||
+ * the A1 rev 2.0 of the board, which does not represent final
 | 
			
		||||
+ * production board.  Things will change, don't expect this file to
 | 
			
		||||
+ * remain compatible info the future.
 | 
			
		||||
+ *
 | 
			
		||||
+ * This file is dual-licensed: you can use it either under the terms
 | 
			
		||||
+ * of the GPL or the X11 license, at your option. Note that this dual
 | 
			
		||||
+ * licensing only applies to this file, and not this project as a
 | 
			
		||||
+ * whole.
 | 
			
		||||
+ *
 | 
			
		||||
+ *  a) This file 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.
 | 
			
		||||
+ *
 | 
			
		||||
+ *     This file 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.
 | 
			
		||||
+ *
 | 
			
		||||
+ * Or, alternatively
 | 
			
		||||
+ *
 | 
			
		||||
+ *  b) Permission is hereby granted, free of charge, to any person
 | 
			
		||||
+ *     obtaining a copy of this software and associated documentation
 | 
			
		||||
+ *     files (the "Software"), to deal in the Software without
 | 
			
		||||
+ *     restriction, including without limitation the rights to use
 | 
			
		||||
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
 | 
			
		||||
+ *     sell copies of the Software, and to permit persons to whom the
 | 
			
		||||
+ *     Software is furnished to do so, subject to the following
 | 
			
		||||
+ *     conditions:
 | 
			
		||||
+ *
 | 
			
		||||
+ *     The above copyright notice and this permission notice shall be
 | 
			
		||||
+ *     included in all copies or substantial portions of the Software.
 | 
			
		||||
+ *
 | 
			
		||||
+ *     THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND
 | 
			
		||||
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 | 
			
		||||
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 | 
			
		||||
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 | 
			
		||||
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
 | 
			
		||||
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 | 
			
		||||
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 | 
			
		||||
+ *     OTHER DEALINGS IN THE SOFTWARE.
 | 
			
		||||
+ */
 | 
			
		||||
+#include <dt-bindings/input/input.h>
 | 
			
		||||
+#include <dt-bindings/gpio/gpio.h>
 | 
			
		||||
+
 | 
			
		||||
+/ {
 | 
			
		||||
+	memory {
 | 
			
		||||
+		device_type = "memory";
 | 
			
		||||
+		reg = <0x00000000 0x10000000>; /* 256 MB */
 | 
			
		||||
+	};
 | 
			
		||||
+
 | 
			
		||||
+	soc {
 | 
			
		||||
+		ranges = <MBUS_ID(0xf0, 0x01) 0 0xf1000000 0x100000
 | 
			
		||||
+			  MBUS_ID(0x01, 0x1d) 0 0xfff00000 0x100000
 | 
			
		||||
+			  MBUS_ID(0x09, 0x19) 0 0xf1100000 0x10000
 | 
			
		||||
+			  MBUS_ID(0x09, 0x15) 0 0xf1110000 0x10000>;
 | 
			
		||||
+
 | 
			
		||||
+		internal-regs {
 | 
			
		||||
+			ethernet@70000 {
 | 
			
		||||
+				pinctrl-0 = <&ge0_rgmii_pins>;
 | 
			
		||||
+				pinctrl-names = "default";
 | 
			
		||||
+				phy = <&phy_dedicated>;
 | 
			
		||||
+				phy-mode = "rgmii-id";
 | 
			
		||||
+				status = "okay";
 | 
			
		||||
+			};
 | 
			
		||||
+
 | 
			
		||||
+			mdio@72004 {
 | 
			
		||||
+				/*
 | 
			
		||||
+				 * Add the phy clock here, so the phy can be
 | 
			
		||||
+				 * accessed to read its IDs prior to binding
 | 
			
		||||
+				 * with the driver.
 | 
			
		||||
+				 */
 | 
			
		||||
+				pinctrl-0 = <&mdio_pins µsom_phy_clk_pins>;
 | 
			
		||||
+				pinctrl-names = "default";
 | 
			
		||||
+
 | 
			
		||||
+				phy_dedicated: ethernet-phy@0 {
 | 
			
		||||
+					/*
 | 
			
		||||
+					 * Annoyingly, the marvell phy driver
 | 
			
		||||
+					 * configures the LED register, rather
 | 
			
		||||
+					 * than preserving reset-loaded setting.
 | 
			
		||||
+					 * We undo that rubbish here.
 | 
			
		||||
+					 */
 | 
			
		||||
+					marvell,reg-init = <3 16 0 0x101e>;
 | 
			
		||||
+					reg = <0>;
 | 
			
		||||
+				};
 | 
			
		||||
+			};
 | 
			
		||||
+
 | 
			
		||||
+			pinctrl@18000 {
 | 
			
		||||
+				microsom_phy_clk_pins: microsom-phy-clk-pins {
 | 
			
		||||
+					marvell,pins = "mpp45";
 | 
			
		||||
+					marvell,function = "ref";
 | 
			
		||||
+				};
 | 
			
		||||
+			};
 | 
			
		||||
+
 | 
			
		||||
+			rtc@a3800 {
 | 
			
		||||
+				/*
 | 
			
		||||
+				 * If the rtc doesn't work, run "date reset"
 | 
			
		||||
+				 * twice in u-boot.
 | 
			
		||||
+				 */
 | 
			
		||||
+				status = "okay";
 | 
			
		||||
+			};
 | 
			
		||||
+
 | 
			
		||||
+			serial@12000 {
 | 
			
		||||
+				pinctrl-0 = <&uart0_pins>;
 | 
			
		||||
+				pinctrl-names = "default";
 | 
			
		||||
+				status = "okay";
 | 
			
		||||
+			};
 | 
			
		||||
+		};
 | 
			
		||||
+	};
 | 
			
		||||
+};
 | 
			
		||||
@@ -0,0 +1,256 @@
 | 
			
		||||
From c49e99c2b25a412623412a461bb751239208b9b3 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Marcin Wojtas <mw@semihalf.com>
 | 
			
		||||
Date: Mon, 14 Mar 2016 09:38:58 +0100
 | 
			
		||||
Subject: [PATCH] ARM: dts: armada-38x: enable buffer manager support on Armada
 | 
			
		||||
 38x boards
 | 
			
		||||
 | 
			
		||||
Since mvneta driver supports using hardware buffer management (BM), in
 | 
			
		||||
order to use it, board files have to be adjusted accordingly. This commit
 | 
			
		||||
enables BM on:
 | 
			
		||||
* A385-DB-AP - each port has its own pool for long and common pool for
 | 
			
		||||
short packets,
 | 
			
		||||
* A388-ClearFog - same as above,
 | 
			
		||||
* A388-DB - to each port unique 'short' and 'long' pools are mapped,
 | 
			
		||||
* A388-GP - same as above.
 | 
			
		||||
 | 
			
		||||
Moreover appropriate entry is added to 'soc' node ranges, as well as "okay"
 | 
			
		||||
status for 'bm' and 'bm-bppi' (internal SRAM) nodes.
 | 
			
		||||
 | 
			
		||||
[gregory.clement@free-electrons.com: add suppport for the ClearFog board]
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
 | 
			
		||||
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
 | 
			
		||||
Acked-by: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
Signed-off-by: David S. Miller <davem@davemloft.net>
 | 
			
		||||
---
 | 
			
		||||
 arch/arm/boot/dts/armada-385-db-ap.dts              | 20 +++++++++++++++++++-
 | 
			
		||||
 arch/arm/boot/dts/armada-388-clearfog.dts           |  6 ++++++
 | 
			
		||||
 arch/arm/boot/dts/armada-388-db.dts                 | 17 ++++++++++++++++-
 | 
			
		||||
 arch/arm/boot/dts/armada-388-gp.dts                 | 17 ++++++++++++++++-
 | 
			
		||||
 arch/arm/boot/dts/armada-38x-solidrun-microsom.dtsi | 15 ++++++++++++++-
 | 
			
		||||
 5 files changed, 71 insertions(+), 4 deletions(-)
 | 
			
		||||
 | 
			
		||||
--- a/arch/arm/boot/dts/armada-385-db-ap.dts
 | 
			
		||||
+++ b/arch/arm/boot/dts/armada-385-db-ap.dts
 | 
			
		||||
@@ -61,7 +61,8 @@
 | 
			
		||||
 		ranges = <MBUS_ID(0xf0, 0x01) 0 0xf1000000 0x100000
 | 
			
		||||
 			  MBUS_ID(0x01, 0x1d) 0 0xfff00000 0x100000
 | 
			
		||||
 			  MBUS_ID(0x09, 0x19) 0 0xf1100000 0x10000
 | 
			
		||||
-			  MBUS_ID(0x09, 0x15) 0 0xf1110000 0x10000>;
 | 
			
		||||
+			  MBUS_ID(0x09, 0x15) 0 0xf1110000 0x10000
 | 
			
		||||
+			  MBUS_ID(0x0c, 0x04) 0 0xf1200000 0x100000>;
 | 
			
		||||
 
 | 
			
		||||
 		internal-regs {
 | 
			
		||||
 			spi1: spi@10680 {
 | 
			
		||||
@@ -138,12 +139,18 @@
 | 
			
		||||
 				status = "okay";
 | 
			
		||||
 				phy = <&phy2>;
 | 
			
		||||
 				phy-mode = "sgmii";
 | 
			
		||||
+				buffer-manager = <&bm>;
 | 
			
		||||
+				bm,pool-long = <1>;
 | 
			
		||||
+				bm,pool-short = <3>;
 | 
			
		||||
 			};
 | 
			
		||||
 
 | 
			
		||||
 			ethernet@34000 {
 | 
			
		||||
 				status = "okay";
 | 
			
		||||
 				phy = <&phy1>;
 | 
			
		||||
 				phy-mode = "sgmii";
 | 
			
		||||
+				buffer-manager = <&bm>;
 | 
			
		||||
+				bm,pool-long = <2>;
 | 
			
		||||
+				bm,pool-short = <3>;
 | 
			
		||||
 			};
 | 
			
		||||
 
 | 
			
		||||
 			ethernet@70000 {
 | 
			
		||||
@@ -157,6 +164,13 @@
 | 
			
		||||
 				status = "okay";
 | 
			
		||||
 				phy = <&phy0>;
 | 
			
		||||
 				phy-mode = "rgmii-id";
 | 
			
		||||
+				buffer-manager = <&bm>;
 | 
			
		||||
+				bm,pool-long = <0>;
 | 
			
		||||
+				bm,pool-short = <3>;
 | 
			
		||||
+			};
 | 
			
		||||
+
 | 
			
		||||
+			bm@c8000 {
 | 
			
		||||
+				status = "okay";
 | 
			
		||||
 			};
 | 
			
		||||
 
 | 
			
		||||
 			nfc: flash@d0000 {
 | 
			
		||||
@@ -178,6 +192,10 @@
 | 
			
		||||
 			};
 | 
			
		||||
 		};
 | 
			
		||||
 
 | 
			
		||||
+		bm-bppi {
 | 
			
		||||
+			status = "okay";
 | 
			
		||||
+		};
 | 
			
		||||
+
 | 
			
		||||
 		pcie-controller {
 | 
			
		||||
 			status = "okay";
 | 
			
		||||
 
 | 
			
		||||
--- a/arch/arm/boot/dts/armada-388-clearfog.dts
 | 
			
		||||
+++ b/arch/arm/boot/dts/armada-388-clearfog.dts
 | 
			
		||||
@@ -78,6 +78,9 @@
 | 
			
		||||
 		internal-regs {
 | 
			
		||||
 			ethernet@30000 {
 | 
			
		||||
 				phy-mode = "sgmii";
 | 
			
		||||
+				buffer-manager = <&bm>;
 | 
			
		||||
+				bm,pool-long = <2>;
 | 
			
		||||
+				bm,pool-short = <1>;
 | 
			
		||||
 				status = "okay";
 | 
			
		||||
 
 | 
			
		||||
 				fixed-link {
 | 
			
		||||
@@ -88,6 +91,9 @@
 | 
			
		||||
 
 | 
			
		||||
 			ethernet@34000 {
 | 
			
		||||
 				phy-mode = "sgmii";
 | 
			
		||||
+				buffer-manager = <&bm>;
 | 
			
		||||
+				bm,pool-long = <3>;
 | 
			
		||||
+				bm,pool-short = <1>;
 | 
			
		||||
 				status = "okay";
 | 
			
		||||
 
 | 
			
		||||
 				fixed-link {
 | 
			
		||||
--- a/arch/arm/boot/dts/armada-388-db.dts
 | 
			
		||||
+++ b/arch/arm/boot/dts/armada-388-db.dts
 | 
			
		||||
@@ -66,7 +66,8 @@
 | 
			
		||||
 		ranges = <MBUS_ID(0xf0, 0x01) 0 0xf1000000 0x100000
 | 
			
		||||
 			  MBUS_ID(0x01, 0x1d) 0 0xfff00000 0x100000
 | 
			
		||||
 			  MBUS_ID(0x09, 0x19) 0 0xf1100000 0x10000
 | 
			
		||||
-			  MBUS_ID(0x09, 0x15) 0 0xf1110000 0x10000>;
 | 
			
		||||
+			  MBUS_ID(0x09, 0x15) 0 0xf1110000 0x10000
 | 
			
		||||
+			  MBUS_ID(0x0c, 0x04) 0 0xf1200000 0x100000>;
 | 
			
		||||
 
 | 
			
		||||
 		internal-regs {
 | 
			
		||||
 			spi@10600 {
 | 
			
		||||
@@ -99,6 +100,9 @@
 | 
			
		||||
 				status = "okay";
 | 
			
		||||
 				phy = <&phy1>;
 | 
			
		||||
 				phy-mode = "rgmii-id";
 | 
			
		||||
+				buffer-manager = <&bm>;
 | 
			
		||||
+				bm,pool-long = <2>;
 | 
			
		||||
+				bm,pool-short = <3>;
 | 
			
		||||
 			};
 | 
			
		||||
 
 | 
			
		||||
 			usb@58000 {
 | 
			
		||||
@@ -109,6 +113,9 @@
 | 
			
		||||
 				status = "okay";
 | 
			
		||||
 				phy = <&phy0>;
 | 
			
		||||
 				phy-mode = "rgmii-id";
 | 
			
		||||
+				buffer-manager = <&bm>;
 | 
			
		||||
+				bm,pool-long = <0>;
 | 
			
		||||
+				bm,pool-short = <1>;
 | 
			
		||||
 			};
 | 
			
		||||
 
 | 
			
		||||
 			mdio@72004 {
 | 
			
		||||
@@ -129,6 +136,10 @@
 | 
			
		||||
 				status = "okay";
 | 
			
		||||
 			};
 | 
			
		||||
 
 | 
			
		||||
+			bm@c8000 {
 | 
			
		||||
+				status = "okay";
 | 
			
		||||
+			};
 | 
			
		||||
+
 | 
			
		||||
 			flash@d0000 {
 | 
			
		||||
 				status = "okay";
 | 
			
		||||
 				num-cs = <1>;
 | 
			
		||||
@@ -169,6 +180,10 @@
 | 
			
		||||
 			};
 | 
			
		||||
 		};
 | 
			
		||||
 
 | 
			
		||||
+		bm-bppi {
 | 
			
		||||
+			status = "okay";
 | 
			
		||||
+		};
 | 
			
		||||
+
 | 
			
		||||
 		pcie-controller {
 | 
			
		||||
 			status = "okay";
 | 
			
		||||
 			/*
 | 
			
		||||
--- a/arch/arm/boot/dts/armada-388-gp.dts
 | 
			
		||||
+++ b/arch/arm/boot/dts/armada-388-gp.dts
 | 
			
		||||
@@ -60,7 +60,8 @@
 | 
			
		||||
 		ranges = <MBUS_ID(0xf0, 0x01) 0 0xf1000000 0x100000
 | 
			
		||||
 			  MBUS_ID(0x01, 0x1d) 0 0xfff00000 0x100000
 | 
			
		||||
 			  MBUS_ID(0x09, 0x19) 0 0xf1100000 0x10000
 | 
			
		||||
-			  MBUS_ID(0x09, 0x15) 0 0xf1110000 0x10000>;
 | 
			
		||||
+			  MBUS_ID(0x09, 0x15) 0 0xf1110000 0x10000
 | 
			
		||||
+			  MBUS_ID(0x0c, 0x04) 0 0xf1200000 0x100000>;
 | 
			
		||||
 
 | 
			
		||||
 		internal-regs {
 | 
			
		||||
 			spi@10600 {
 | 
			
		||||
@@ -133,6 +134,9 @@
 | 
			
		||||
 				status = "okay";
 | 
			
		||||
 				phy = <&phy1>;
 | 
			
		||||
 				phy-mode = "rgmii-id";
 | 
			
		||||
+				buffer-manager = <&bm>;
 | 
			
		||||
+				bm,pool-long = <2>;
 | 
			
		||||
+				bm,pool-short = <3>;
 | 
			
		||||
 			};
 | 
			
		||||
 
 | 
			
		||||
 			/* CON4 */
 | 
			
		||||
@@ -152,6 +156,9 @@
 | 
			
		||||
 				status = "okay";
 | 
			
		||||
 				phy = <&phy0>;
 | 
			
		||||
 				phy-mode = "rgmii-id";
 | 
			
		||||
+				buffer-manager = <&bm>;
 | 
			
		||||
+				bm,pool-long = <0>;
 | 
			
		||||
+				bm,pool-short = <1>;
 | 
			
		||||
 			};
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
@@ -186,6 +193,10 @@
 | 
			
		||||
 				};
 | 
			
		||||
 			};
 | 
			
		||||
 
 | 
			
		||||
+			bm@c8000 {
 | 
			
		||||
+				status = "okay";
 | 
			
		||||
+			};
 | 
			
		||||
+
 | 
			
		||||
 			sata@e0000 {
 | 
			
		||||
 				pinctrl-names = "default";
 | 
			
		||||
 				pinctrl-0 = <&sata2_pins>, <&sata3_pins>;
 | 
			
		||||
@@ -240,6 +251,10 @@
 | 
			
		||||
 			};
 | 
			
		||||
 		};
 | 
			
		||||
 
 | 
			
		||||
+		bm-bppi {
 | 
			
		||||
+			status = "okay";
 | 
			
		||||
+		};
 | 
			
		||||
+
 | 
			
		||||
 		pcie-controller {
 | 
			
		||||
 			status = "okay";
 | 
			
		||||
 			/*
 | 
			
		||||
--- a/arch/arm/boot/dts/armada-38x-solidrun-microsom.dtsi
 | 
			
		||||
+++ b/arch/arm/boot/dts/armada-38x-solidrun-microsom.dtsi
 | 
			
		||||
@@ -58,7 +58,8 @@
 | 
			
		||||
 		ranges = <MBUS_ID(0xf0, 0x01) 0 0xf1000000 0x100000
 | 
			
		||||
 			  MBUS_ID(0x01, 0x1d) 0 0xfff00000 0x100000
 | 
			
		||||
 			  MBUS_ID(0x09, 0x19) 0 0xf1100000 0x10000
 | 
			
		||||
-			  MBUS_ID(0x09, 0x15) 0 0xf1110000 0x10000>;
 | 
			
		||||
+			  MBUS_ID(0x09, 0x15) 0 0xf1110000 0x10000
 | 
			
		||||
+			  MBUS_ID(0x0c, 0x04) 0 0xf1200000 0x100000>;
 | 
			
		||||
 
 | 
			
		||||
 		internal-regs {
 | 
			
		||||
 			ethernet@70000 {
 | 
			
		||||
@@ -66,6 +67,9 @@
 | 
			
		||||
 				pinctrl-names = "default";
 | 
			
		||||
 				phy = <&phy_dedicated>;
 | 
			
		||||
 				phy-mode = "rgmii-id";
 | 
			
		||||
+				buffer-manager = <&bm>;
 | 
			
		||||
+				bm,pool-long = <0>;
 | 
			
		||||
+				bm,pool-short = <1>;
 | 
			
		||||
 				status = "okay";
 | 
			
		||||
 			};
 | 
			
		||||
 
 | 
			
		||||
@@ -110,6 +114,15 @@
 | 
			
		||||
 				pinctrl-names = "default";
 | 
			
		||||
 				status = "okay";
 | 
			
		||||
 			};
 | 
			
		||||
+
 | 
			
		||||
+			bm@c8000 {
 | 
			
		||||
+				status = "okay";
 | 
			
		||||
+			};
 | 
			
		||||
 		};
 | 
			
		||||
+
 | 
			
		||||
+		bm-bppi {
 | 
			
		||||
+			status = "okay";
 | 
			
		||||
+		};
 | 
			
		||||
+
 | 
			
		||||
 	};
 | 
			
		||||
 };
 | 
			
		||||
@@ -0,0 +1,41 @@
 | 
			
		||||
From d261861ab52623e34a25fe6ae76714456edda033 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Russell King <rmk+kernel@armlinux.org.uk>
 | 
			
		||||
Date: Sun, 10 Jul 2016 16:27:38 +0100
 | 
			
		||||
Subject: [PATCH] ARM: dts: armada-388-clearfog: remove duplicate mdio entry
 | 
			
		||||
 | 
			
		||||
The clearfog DTS should not be defining the on-board phy, this device
 | 
			
		||||
is located on the microsom.  Remove the duplicated definition.
 | 
			
		||||
 | 
			
		||||
Reported-by: Jon Nettleton <jon@solid-run.com>
 | 
			
		||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
 | 
			
		||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
 | 
			
		||||
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
 | 
			
		||||
---
 | 
			
		||||
 arch/arm/boot/dts/armada-388-clearfog.dts | 16 ----------------
 | 
			
		||||
 1 file changed, 16 deletions(-)
 | 
			
		||||
 | 
			
		||||
--- a/arch/arm/boot/dts/armada-388-clearfog.dts
 | 
			
		||||
+++ b/arch/arm/boot/dts/armada-388-clearfog.dts
 | 
			
		||||
@@ -239,22 +239,6 @@
 | 
			
		||||
 				status = "okay";
 | 
			
		||||
 			};
 | 
			
		||||
 
 | 
			
		||||
-			mdio@72004 {
 | 
			
		||||
-				pinctrl-0 = <&mdio_pins>;
 | 
			
		||||
-				pinctrl-names = "default";
 | 
			
		||||
-
 | 
			
		||||
-				phy_dedicated: ethernet-phy@0 {
 | 
			
		||||
-					/*
 | 
			
		||||
-					 * Annoyingly, the marvell phy driver
 | 
			
		||||
-					 * configures the LED register, rather
 | 
			
		||||
-					 * than preserving reset-loaded setting.
 | 
			
		||||
-					 * We undo that rubbish here.
 | 
			
		||||
-					 */
 | 
			
		||||
-					marvell,reg-init = <3 16 0 0x101e>;
 | 
			
		||||
-					reg = <0>;
 | 
			
		||||
-				};
 | 
			
		||||
-			};
 | 
			
		||||
-
 | 
			
		||||
 			pinctrl@18000 {
 | 
			
		||||
 				clearfog_dsa0_clk_pins: clearfog-dsa0-clk-pins {
 | 
			
		||||
 					marvell,pins = "mpp46";
 | 
			
		||||
							
								
								
									
										62
									
								
								target/linux/mvebu/patches-4.4/100-find_active_root.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								target/linux/mvebu/patches-4.4/100-find_active_root.patch
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,62 @@
 | 
			
		||||
The WRT1900AC among other Linksys routers uses a dual-firmware layout.
 | 
			
		||||
Dynamically rename the active partition to "ubi".
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
 | 
			
		||||
 | 
			
		||||
--- a/drivers/mtd/ofpart.c
 | 
			
		||||
+++ b/drivers/mtd/ofpart.c
 | 
			
		||||
@@ -25,6 +25,8 @@ static bool node_has_compatible(struct d
 | 
			
		||||
 	return of_get_property(pp, "compatible", NULL);
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
+static int mangled_rootblock;
 | 
			
		||||
+
 | 
			
		||||
 static int parse_ofpart_partitions(struct mtd_info *master,
 | 
			
		||||
 				   struct mtd_partition **pparts,
 | 
			
		||||
 				   struct mtd_part_parser_data *data)
 | 
			
		||||
@@ -32,6 +34,7 @@ static int parse_ofpart_partitions(struc
 | 
			
		||||
 	struct device_node *mtd_node;
 | 
			
		||||
 	struct device_node *ofpart_node;
 | 
			
		||||
 	const char *partname;
 | 
			
		||||
+	const char *owrtpart = "ubi";
 | 
			
		||||
 	struct device_node *pp;
 | 
			
		||||
 	int nr_parts, i, ret = 0;
 | 
			
		||||
 	bool dedicated = true;
 | 
			
		||||
@@ -110,9 +113,15 @@ static int parse_ofpart_partitions(struc
 | 
			
		||||
 		(*pparts)[i].offset = of_read_number(reg, a_cells);
 | 
			
		||||
 		(*pparts)[i].size = of_read_number(reg + a_cells, s_cells);
 | 
			
		||||
 
 | 
			
		||||
-		partname = of_get_property(pp, "label", &len);
 | 
			
		||||
-		if (!partname)
 | 
			
		||||
-			partname = of_get_property(pp, "name", &len);
 | 
			
		||||
+		if (mangled_rootblock && (i == mangled_rootblock)) {
 | 
			
		||||
+				partname = owrtpart;
 | 
			
		||||
+		} else {
 | 
			
		||||
+			partname = of_get_property(pp, "label", &len);
 | 
			
		||||
+
 | 
			
		||||
+			if (!partname)
 | 
			
		||||
+				partname = of_get_property(pp, "name", &len);
 | 
			
		||||
+		}
 | 
			
		||||
+
 | 
			
		||||
 		(*pparts)[i].name = partname;
 | 
			
		||||
 
 | 
			
		||||
 		if (of_get_property(pp, "read-only", &len))
 | 
			
		||||
@@ -215,6 +224,18 @@ static int __init ofpart_parser_init(voi
 | 
			
		||||
 	return 0;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
+static int __init active_root(char *str)
 | 
			
		||||
+{
 | 
			
		||||
+	get_option(&str, &mangled_rootblock);
 | 
			
		||||
+
 | 
			
		||||
+	if (!mangled_rootblock)
 | 
			
		||||
+		return 1;
 | 
			
		||||
+
 | 
			
		||||
+	return 1;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+__setup("mangled_rootblock=", active_root);
 | 
			
		||||
+
 | 
			
		||||
 static void __exit ofpart_parser_exit(void)
 | 
			
		||||
 {
 | 
			
		||||
 	deregister_mtd_parser(&ofpart_parser);
 | 
			
		||||
							
								
								
									
										15
									
								
								target/linux/mvebu/patches-4.4/102-revert_i2c_delay.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								target/linux/mvebu/patches-4.4/102-revert_i2c_delay.patch
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
			
		||||
--- a/arch/arm/boot/dts/armada-xp.dtsi
 | 
			
		||||
+++ b/arch/arm/boot/dts/armada-xp.dtsi
 | 
			
		||||
@@ -98,12 +98,10 @@
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
 			i2c0: i2c@11000 {
 | 
			
		||||
-				compatible = "marvell,mv78230-i2c", "marvell,mv64xxx-i2c";
 | 
			
		||||
 				reg = <0x11000 0x100>;
 | 
			
		||||
 			};
 | 
			
		||||
 
 | 
			
		||||
 			i2c1: i2c@11100 {
 | 
			
		||||
-				compatible = "marvell,mv78230-i2c", "marvell,mv64xxx-i2c";
 | 
			
		||||
 				reg = <0x11100 0x100>;
 | 
			
		||||
 			};
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,13 @@
 | 
			
		||||
Remove a BUG() call that would crash on a race condition that should
 | 
			
		||||
otherwise be harmless.
 | 
			
		||||
 | 
			
		||||
--- a/drivers/mtd/nand/pxa3xx_nand.c
 | 
			
		||||
+++ b/drivers/mtd/nand/pxa3xx_nand.c
 | 
			
		||||
@@ -701,7 +701,6 @@ static void handle_data_pio(struct pxa3x
 | 
			
		||||
 	default:
 | 
			
		||||
 		dev_err(&info->pdev->dev, "%s: invalid state %d\n", __func__,
 | 
			
		||||
 				info->state);
 | 
			
		||||
-		BUG();
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
 	/* Update buffer pointers for multi-page read/write */
 | 
			
		||||
@@ -0,0 +1,10 @@
 | 
			
		||||
--- a/arch/arm/boot/dts/armada-xp-linksys-mamba.dts
 | 
			
		||||
+++ b/arch/arm/boot/dts/armada-xp-linksys-mamba.dts
 | 
			
		||||
@@ -298,7 +298,6 @@
 | 
			
		||||
 			nand@d0000 {
 | 
			
		||||
 				status = "okay";
 | 
			
		||||
 				num-cs = <1>;
 | 
			
		||||
-				marvell,nand-keep-config;
 | 
			
		||||
 				marvell,nand-enable-arbiter;
 | 
			
		||||
 				nand-on-flash-bbt;
 | 
			
		||||
 				nand-ecc-strength = <4>;
 | 
			
		||||
@@ -0,0 +1,107 @@
 | 
			
		||||
--- a/arch/arm/boot/dts/armada-385-linksys.dtsi
 | 
			
		||||
+++ b/arch/arm/boot/dts/armada-385-linksys.dtsi
 | 
			
		||||
@@ -59,7 +59,8 @@
 | 
			
		||||
 		ranges = <MBUS_ID(0xf0, 0x01) 0 0xf1000000 0x100000
 | 
			
		||||
 			  MBUS_ID(0x01, 0x1d) 0 0xfff00000 0x100000
 | 
			
		||||
 			  MBUS_ID(0x09, 0x19) 0 0xf1100000 0x10000
 | 
			
		||||
-			  MBUS_ID(0x09, 0x15) 0 0xf1110000 0x10000>;
 | 
			
		||||
+			  MBUS_ID(0x09, 0x15) 0 0xf1110000 0x10000
 | 
			
		||||
+			  MBUS_ID(0x0c, 0x04) 0 0xf1200000 0x100000>;
 | 
			
		||||
 
 | 
			
		||||
 		internal-regs {
 | 
			
		||||
 
 | 
			
		||||
@@ -93,6 +94,9 @@
 | 
			
		||||
 			ethernet@70000 {
 | 
			
		||||
 				status = "okay";
 | 
			
		||||
 				phy-mode = "rgmii-id";
 | 
			
		||||
+				buffer-manager = <&bm>;
 | 
			
		||||
+				bm,pool-long = <0>;
 | 
			
		||||
+				bm,pool-short = <3>;
 | 
			
		||||
 				fixed-link {
 | 
			
		||||
 					speed = <1000>;
 | 
			
		||||
 					full-duplex;
 | 
			
		||||
@@ -102,6 +106,9 @@
 | 
			
		||||
 			ethernet@34000 {
 | 
			
		||||
 				status = "okay";
 | 
			
		||||
 				phy-mode = "sgmii";
 | 
			
		||||
+				buffer-manager = <&bm>;
 | 
			
		||||
+				bm,pool-long = <2>;
 | 
			
		||||
+				bm,pool-short = <3>;
 | 
			
		||||
 				fixed-link {
 | 
			
		||||
 					speed = <1000>;
 | 
			
		||||
 					full-duplex;
 | 
			
		||||
@@ -112,6 +119,10 @@
 | 
			
		||||
 				status = "okay";
 | 
			
		||||
 			};
 | 
			
		||||
 
 | 
			
		||||
+			bm@c8000 {
 | 
			
		||||
+				status = "okay";
 | 
			
		||||
+			};
 | 
			
		||||
+
 | 
			
		||||
 			sata@a8000 {
 | 
			
		||||
 				status = "okay";
 | 
			
		||||
 			};
 | 
			
		||||
@@ -198,6 +209,10 @@
 | 
			
		||||
 			};
 | 
			
		||||
 		};
 | 
			
		||||
 
 | 
			
		||||
+		bm-bppi {
 | 
			
		||||
+			status = "okay";
 | 
			
		||||
+		};
 | 
			
		||||
+
 | 
			
		||||
 		pcie-controller {
 | 
			
		||||
 			status = "okay";
 | 
			
		||||
 
 | 
			
		||||
--- a/arch/arm/boot/dts/armada-xp-linksys-mamba.dts
 | 
			
		||||
+++ b/arch/arm/boot/dts/armada-xp-linksys-mamba.dts
 | 
			
		||||
@@ -71,7 +71,8 @@
 | 
			
		||||
 		ranges = <MBUS_ID(0xf0, 0x01) 0 0 0xf1000000 0x100000
 | 
			
		||||
 			  MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000
 | 
			
		||||
 			  MBUS_ID(0x09, 0x09) 0 0 0xf1100000 0x10000
 | 
			
		||||
-			  MBUS_ID(0x09, 0x05) 0 0 0xf1110000 0x10000>;
 | 
			
		||||
+			  MBUS_ID(0x09, 0x05) 0 0 0xf1110000 0x10000
 | 
			
		||||
+			  MBUS_ID(0x0c, 0x04) 0 0 0xf1200000 0x100000>;
 | 
			
		||||
 
 | 
			
		||||
 		pcie-controller {
 | 
			
		||||
 			status = "okay";
 | 
			
		||||
@@ -205,6 +206,9 @@
 | 
			
		||||
 				pinctrl-names = "default";
 | 
			
		||||
 				status = "okay";
 | 
			
		||||
 				phy-mode = "rgmii-id";
 | 
			
		||||
+				buffer-manager = <&bm>;
 | 
			
		||||
+				bm,pool-long = <0>;
 | 
			
		||||
+				bm,pool-short = <3>;
 | 
			
		||||
 				fixed-link {
 | 
			
		||||
 					speed = <1000>;
 | 
			
		||||
 					full-duplex;
 | 
			
		||||
@@ -216,12 +220,19 @@
 | 
			
		||||
 				pinctrl-names = "default";
 | 
			
		||||
 				status = "okay";
 | 
			
		||||
 				phy-mode = "rgmii-id";
 | 
			
		||||
+				buffer-manager = <&bm>;
 | 
			
		||||
+				bm,pool-long = <1>;
 | 
			
		||||
+				bm,pool-short = <3>;
 | 
			
		||||
 				fixed-link {
 | 
			
		||||
 					speed = <1000>;
 | 
			
		||||
 					full-duplex;
 | 
			
		||||
 				};
 | 
			
		||||
 			};
 | 
			
		||||
 
 | 
			
		||||
+			bm@c0000 {
 | 
			
		||||
+				status = "okay";
 | 
			
		||||
+			};
 | 
			
		||||
+
 | 
			
		||||
 			/* USB part of the eSATA/USB 2.0 port */
 | 
			
		||||
 			usb@50000 {
 | 
			
		||||
 				status = "okay";
 | 
			
		||||
@@ -379,6 +390,10 @@
 | 
			
		||||
 				};
 | 
			
		||||
 			};
 | 
			
		||||
 		};
 | 
			
		||||
+
 | 
			
		||||
+		bm-bppi {
 | 
			
		||||
+			status = "okay";
 | 
			
		||||
+		};
 | 
			
		||||
 	};
 | 
			
		||||
 
 | 
			
		||||
 	gpio_keys {
 | 
			
		||||
@@ -0,0 +1,69 @@
 | 
			
		||||
Revert "mtd: pxa3xx-nand: handle PIO in threaded interrupt"
 | 
			
		||||
 | 
			
		||||
This reverts commit 24542257a3b987025d4b998ec2d15e556c98ad3f
 | 
			
		||||
This upstream change has been causing spurious timeouts on accesses
 | 
			
		||||
to the NAND flash if something else on the system is causing
 | 
			
		||||
significant latency.
 | 
			
		||||
 | 
			
		||||
Nothing guarantees that the thread will run in time, so the
 | 
			
		||||
usual timeout is unreliable.
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
 | 
			
		||||
 | 
			
		||||
--- a/drivers/mtd/nand/pxa3xx_nand.c
 | 
			
		||||
+++ b/drivers/mtd/nand/pxa3xx_nand.c
 | 
			
		||||
@@ -765,24 +765,11 @@ static void start_data_dma(struct pxa3xx
 | 
			
		||||
 		__func__, direction, info->dma_cookie, info->sg.length);
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
-static irqreturn_t pxa3xx_nand_irq_thread(int irq, void *data)
 | 
			
		||||
-{
 | 
			
		||||
-	struct pxa3xx_nand_info *info = data;
 | 
			
		||||
-
 | 
			
		||||
-	handle_data_pio(info);
 | 
			
		||||
-
 | 
			
		||||
-	info->state = STATE_CMD_DONE;
 | 
			
		||||
-	nand_writel(info, NDSR, NDSR_WRDREQ | NDSR_RDDREQ);
 | 
			
		||||
-
 | 
			
		||||
-	return IRQ_HANDLED;
 | 
			
		||||
-}
 | 
			
		||||
-
 | 
			
		||||
 static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
 | 
			
		||||
 {
 | 
			
		||||
 	struct pxa3xx_nand_info *info = devid;
 | 
			
		||||
 	unsigned int status, is_completed = 0, is_ready = 0;
 | 
			
		||||
 	unsigned int ready, cmd_done;
 | 
			
		||||
-	irqreturn_t ret = IRQ_HANDLED;
 | 
			
		||||
 
 | 
			
		||||
 	if (info->cs == 0) {
 | 
			
		||||
 		ready           = NDSR_FLASH_RDY;
 | 
			
		||||
@@ -824,8 +811,7 @@ static irqreturn_t pxa3xx_nand_irq(int i
 | 
			
		||||
 		} else {
 | 
			
		||||
 			info->state = (status & NDSR_RDDREQ) ?
 | 
			
		||||
 				      STATE_PIO_READING : STATE_PIO_WRITING;
 | 
			
		||||
-			ret = IRQ_WAKE_THREAD;
 | 
			
		||||
-			goto NORMAL_IRQ_EXIT;
 | 
			
		||||
+			handle_data_pio(info);
 | 
			
		||||
 		}
 | 
			
		||||
 	}
 | 
			
		||||
 	if (status & cmd_done) {
 | 
			
		||||
@@ -870,7 +856,7 @@ static irqreturn_t pxa3xx_nand_irq(int i
 | 
			
		||||
 	if (is_ready)
 | 
			
		||||
 		complete(&info->dev_ready);
 | 
			
		||||
 NORMAL_IRQ_EXIT:
 | 
			
		||||
-	return ret;
 | 
			
		||||
+	return IRQ_HANDLED;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
 static inline int is_buf_blank(uint8_t *buf, size_t len)
 | 
			
		||||
@@ -1849,9 +1835,7 @@ static int alloc_nand_resource(struct pl
 | 
			
		||||
 	/* initialize all interrupts to be disabled */
 | 
			
		||||
 	disable_int(info, NDSR_MASK);
 | 
			
		||||
 
 | 
			
		||||
-	ret = request_threaded_irq(irq, pxa3xx_nand_irq,
 | 
			
		||||
-				   pxa3xx_nand_irq_thread, IRQF_ONESHOT,
 | 
			
		||||
-				   pdev->name, info);
 | 
			
		||||
+	ret = request_irq(irq, pxa3xx_nand_irq, 0, pdev->name, info);
 | 
			
		||||
 	if (ret < 0) {
 | 
			
		||||
 		dev_err(&pdev->dev, "failed to request IRQ\n");
 | 
			
		||||
 		goto fail_free_buf;
 | 
			
		||||
@@ -0,0 +1,306 @@
 | 
			
		||||
From 4d5621372f6e7ddbfd5879602f82073987bcc722 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
Date: Sun, 20 Sep 2015 09:57:10 +0100
 | 
			
		||||
Subject: [PATCH 709/744] phy: move fixed_phy MII register generation to a
 | 
			
		||||
 library
 | 
			
		||||
 | 
			
		||||
Move the fixed_phy MII register generation to a library to allow other
 | 
			
		||||
software phy implementations to use this code.
 | 
			
		||||
 | 
			
		||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
 | 
			
		||||
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
---
 | 
			
		||||
 drivers/net/phy/Kconfig     |   4 ++
 | 
			
		||||
 drivers/net/phy/Makefile    |   3 +-
 | 
			
		||||
 drivers/net/phy/fixed_phy.c |  95 ++-------------------------------
 | 
			
		||||
 drivers/net/phy/swphy.c     | 126 ++++++++++++++++++++++++++++++++++++++++++++
 | 
			
		||||
 drivers/net/phy/swphy.h     |   8 +++
 | 
			
		||||
 5 files changed, 143 insertions(+), 93 deletions(-)
 | 
			
		||||
 create mode 100644 drivers/net/phy/swphy.c
 | 
			
		||||
 create mode 100644 drivers/net/phy/swphy.h
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/phy/Kconfig
 | 
			
		||||
+++ b/drivers/net/phy/Kconfig
 | 
			
		||||
@@ -26,6 +26,9 @@ config SWCONFIG_LEDS
 | 
			
		||||
 	bool "Switch LED trigger support"
 | 
			
		||||
 	depends on (SWCONFIG && LEDS_TRIGGERS)
 | 
			
		||||
 
 | 
			
		||||
+config SWPHY
 | 
			
		||||
+	bool
 | 
			
		||||
+
 | 
			
		||||
 comment "MII PHY device drivers"
 | 
			
		||||
 
 | 
			
		||||
 config AQUANTIA_PHY
 | 
			
		||||
@@ -205,6 +208,7 @@ config RTL8306_PHY
 | 
			
		||||
 config FIXED_PHY
 | 
			
		||||
 	tristate "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
 | 
			
		||||
 	depends on PHYLIB
 | 
			
		||||
+	select SWPHY
 | 
			
		||||
 	---help---
 | 
			
		||||
 	  Adds the platform "fixed" MDIO Bus to cover the boards that use
 | 
			
		||||
 	  PHYs that are not connected to the real MDIO bus.
 | 
			
		||||
--- a/drivers/net/phy/Makefile
 | 
			
		||||
+++ b/drivers/net/phy/Makefile
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
 # Makefile for Linux PHY drivers
 | 
			
		||||
 
 | 
			
		||||
-libphy-objs			:= phy.o phy_device.o mdio_bus.o
 | 
			
		||||
+libphy-y			:= phy.o phy_device.o mdio_bus.o
 | 
			
		||||
+libphy-$(CONFIG_SWPHY)		+= swphy.o
 | 
			
		||||
 
 | 
			
		||||
 obj-$(CONFIG_MDIO_BOARDINFO)	+= mdio-boardinfo.o
 | 
			
		||||
 
 | 
			
		||||
--- a/drivers/net/phy/fixed_phy.c
 | 
			
		||||
+++ b/drivers/net/phy/fixed_phy.c
 | 
			
		||||
@@ -24,6 +24,8 @@
 | 
			
		||||
 #include <linux/of.h>
 | 
			
		||||
 #include <linux/gpio.h>
 | 
			
		||||
 
 | 
			
		||||
+#include "swphy.h"
 | 
			
		||||
+
 | 
			
		||||
 #define MII_REGS_NUM 29
 | 
			
		||||
 
 | 
			
		||||
 struct fixed_mdio_bus {
 | 
			
		||||
@@ -49,101 +51,10 @@ static struct fixed_mdio_bus platform_fm
 | 
			
		||||
 
 | 
			
		||||
 static int fixed_phy_update_regs(struct fixed_phy *fp)
 | 
			
		||||
 {
 | 
			
		||||
-	u16 bmsr = BMSR_ANEGCAPABLE;
 | 
			
		||||
-	u16 bmcr = 0;
 | 
			
		||||
-	u16 lpagb = 0;
 | 
			
		||||
-	u16 lpa = 0;
 | 
			
		||||
-
 | 
			
		||||
 	if (gpio_is_valid(fp->link_gpio))
 | 
			
		||||
 		fp->status.link = !!gpio_get_value_cansleep(fp->link_gpio);
 | 
			
		||||
 
 | 
			
		||||
-	if (fp->status.duplex) {
 | 
			
		||||
-		switch (fp->status.speed) {
 | 
			
		||||
-		case 1000:
 | 
			
		||||
-			bmsr |= BMSR_ESTATEN;
 | 
			
		||||
-			break;
 | 
			
		||||
-		case 100:
 | 
			
		||||
-			bmsr |= BMSR_100FULL;
 | 
			
		||||
-			break;
 | 
			
		||||
-		case 10:
 | 
			
		||||
-			bmsr |= BMSR_10FULL;
 | 
			
		||||
-			break;
 | 
			
		||||
-		default:
 | 
			
		||||
-			break;
 | 
			
		||||
-		}
 | 
			
		||||
-	} else {
 | 
			
		||||
-		switch (fp->status.speed) {
 | 
			
		||||
-		case 1000:
 | 
			
		||||
-			bmsr |= BMSR_ESTATEN;
 | 
			
		||||
-			break;
 | 
			
		||||
-		case 100:
 | 
			
		||||
-			bmsr |= BMSR_100HALF;
 | 
			
		||||
-			break;
 | 
			
		||||
-		case 10:
 | 
			
		||||
-			bmsr |= BMSR_10HALF;
 | 
			
		||||
-			break;
 | 
			
		||||
-		default:
 | 
			
		||||
-			break;
 | 
			
		||||
-		}
 | 
			
		||||
-	}
 | 
			
		||||
-
 | 
			
		||||
-	if (fp->status.link) {
 | 
			
		||||
-		bmsr |= BMSR_LSTATUS | BMSR_ANEGCOMPLETE;
 | 
			
		||||
-
 | 
			
		||||
-		if (fp->status.duplex) {
 | 
			
		||||
-			bmcr |= BMCR_FULLDPLX;
 | 
			
		||||
-
 | 
			
		||||
-			switch (fp->status.speed) {
 | 
			
		||||
-			case 1000:
 | 
			
		||||
-				bmcr |= BMCR_SPEED1000;
 | 
			
		||||
-				lpagb |= LPA_1000FULL;
 | 
			
		||||
-				break;
 | 
			
		||||
-			case 100:
 | 
			
		||||
-				bmcr |= BMCR_SPEED100;
 | 
			
		||||
-				lpa |= LPA_100FULL;
 | 
			
		||||
-				break;
 | 
			
		||||
-			case 10:
 | 
			
		||||
-				lpa |= LPA_10FULL;
 | 
			
		||||
-				break;
 | 
			
		||||
-			default:
 | 
			
		||||
-				pr_warn("fixed phy: unknown speed\n");
 | 
			
		||||
-				return -EINVAL;
 | 
			
		||||
-			}
 | 
			
		||||
-		} else {
 | 
			
		||||
-			switch (fp->status.speed) {
 | 
			
		||||
-			case 1000:
 | 
			
		||||
-				bmcr |= BMCR_SPEED1000;
 | 
			
		||||
-				lpagb |= LPA_1000HALF;
 | 
			
		||||
-				break;
 | 
			
		||||
-			case 100:
 | 
			
		||||
-				bmcr |= BMCR_SPEED100;
 | 
			
		||||
-				lpa |= LPA_100HALF;
 | 
			
		||||
-				break;
 | 
			
		||||
-			case 10:
 | 
			
		||||
-				lpa |= LPA_10HALF;
 | 
			
		||||
-				break;
 | 
			
		||||
-			default:
 | 
			
		||||
-				pr_warn("fixed phy: unknown speed\n");
 | 
			
		||||
-			return -EINVAL;
 | 
			
		||||
-			}
 | 
			
		||||
-		}
 | 
			
		||||
-
 | 
			
		||||
-		if (fp->status.pause)
 | 
			
		||||
-			lpa |= LPA_PAUSE_CAP;
 | 
			
		||||
-
 | 
			
		||||
-		if (fp->status.asym_pause)
 | 
			
		||||
-			lpa |= LPA_PAUSE_ASYM;
 | 
			
		||||
-	}
 | 
			
		||||
-
 | 
			
		||||
-	fp->regs[MII_PHYSID1] = 0;
 | 
			
		||||
-	fp->regs[MII_PHYSID2] = 0;
 | 
			
		||||
-
 | 
			
		||||
-	fp->regs[MII_BMSR] = bmsr;
 | 
			
		||||
-	fp->regs[MII_BMCR] = bmcr;
 | 
			
		||||
-	fp->regs[MII_LPA] = lpa;
 | 
			
		||||
-	fp->regs[MII_STAT1000] = lpagb;
 | 
			
		||||
-
 | 
			
		||||
-	return 0;
 | 
			
		||||
+	return swphy_update_regs(fp->regs, &fp->status);
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
 static int fixed_mdio_read(struct mii_bus *bus, int phy_addr, int reg_num)
 | 
			
		||||
--- /dev/null
 | 
			
		||||
+++ b/drivers/net/phy/swphy.c
 | 
			
		||||
@@ -0,0 +1,126 @@
 | 
			
		||||
+/*
 | 
			
		||||
+ * Software PHY emulation
 | 
			
		||||
+ *
 | 
			
		||||
+ * Code taken from fixed_phy.c by Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
+ *
 | 
			
		||||
+ * Author: Vitaly Bordug <vbordug@ru.mvista.com>
 | 
			
		||||
+ *         Anton Vorontsov <avorontsov@ru.mvista.com>
 | 
			
		||||
+ *
 | 
			
		||||
+ * Copyright (c) 2006-2007 MontaVista Software, Inc.
 | 
			
		||||
+ *
 | 
			
		||||
+ * 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.
 | 
			
		||||
+ */
 | 
			
		||||
+#include <linux/export.h>
 | 
			
		||||
+#include <linux/mii.h>
 | 
			
		||||
+#include <linux/phy.h>
 | 
			
		||||
+#include <linux/phy_fixed.h>
 | 
			
		||||
+
 | 
			
		||||
+#include "swphy.h"
 | 
			
		||||
+
 | 
			
		||||
+/**
 | 
			
		||||
+ * swphy_update_regs - update MII register array with fixed phy state
 | 
			
		||||
+ * @regs: array of 32 registers to update
 | 
			
		||||
+ * @state: fixed phy status
 | 
			
		||||
+ *
 | 
			
		||||
+ * Update the array of MII registers with the fixed phy link, speed,
 | 
			
		||||
+ * duplex and pause mode settings.
 | 
			
		||||
+ */
 | 
			
		||||
+int swphy_update_regs(u16 *regs, const struct fixed_phy_status *state)
 | 
			
		||||
+{
 | 
			
		||||
+	u16 bmsr = BMSR_ANEGCAPABLE;
 | 
			
		||||
+	u16 bmcr = 0;
 | 
			
		||||
+	u16 lpagb = 0;
 | 
			
		||||
+	u16 lpa = 0;
 | 
			
		||||
+
 | 
			
		||||
+	if (state->duplex) {
 | 
			
		||||
+		switch (state->speed) {
 | 
			
		||||
+		case 1000:
 | 
			
		||||
+			bmsr |= BMSR_ESTATEN;
 | 
			
		||||
+			break;
 | 
			
		||||
+		case 100:
 | 
			
		||||
+			bmsr |= BMSR_100FULL;
 | 
			
		||||
+			break;
 | 
			
		||||
+		case 10:
 | 
			
		||||
+			bmsr |= BMSR_10FULL;
 | 
			
		||||
+			break;
 | 
			
		||||
+		default:
 | 
			
		||||
+			break;
 | 
			
		||||
+		}
 | 
			
		||||
+	} else {
 | 
			
		||||
+		switch (state->speed) {
 | 
			
		||||
+		case 1000:
 | 
			
		||||
+			bmsr |= BMSR_ESTATEN;
 | 
			
		||||
+			break;
 | 
			
		||||
+		case 100:
 | 
			
		||||
+			bmsr |= BMSR_100HALF;
 | 
			
		||||
+			break;
 | 
			
		||||
+		case 10:
 | 
			
		||||
+			bmsr |= BMSR_10HALF;
 | 
			
		||||
+			break;
 | 
			
		||||
+		default:
 | 
			
		||||
+			break;
 | 
			
		||||
+		}
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	if (state->link) {
 | 
			
		||||
+		bmsr |= BMSR_LSTATUS | BMSR_ANEGCOMPLETE;
 | 
			
		||||
+
 | 
			
		||||
+		if (state->duplex) {
 | 
			
		||||
+			bmcr |= BMCR_FULLDPLX;
 | 
			
		||||
+
 | 
			
		||||
+			switch (state->speed) {
 | 
			
		||||
+			case 1000:
 | 
			
		||||
+				bmcr |= BMCR_SPEED1000;
 | 
			
		||||
+				lpagb |= LPA_1000FULL;
 | 
			
		||||
+				break;
 | 
			
		||||
+			case 100:
 | 
			
		||||
+				bmcr |= BMCR_SPEED100;
 | 
			
		||||
+				lpa |= LPA_100FULL;
 | 
			
		||||
+				break;
 | 
			
		||||
+			case 10:
 | 
			
		||||
+				lpa |= LPA_10FULL;
 | 
			
		||||
+				break;
 | 
			
		||||
+			default:
 | 
			
		||||
+				pr_warn("swphy: unknown speed\n");
 | 
			
		||||
+				return -EINVAL;
 | 
			
		||||
+			}
 | 
			
		||||
+		} else {
 | 
			
		||||
+			switch (state->speed) {
 | 
			
		||||
+			case 1000:
 | 
			
		||||
+				bmcr |= BMCR_SPEED1000;
 | 
			
		||||
+				lpagb |= LPA_1000HALF;
 | 
			
		||||
+				break;
 | 
			
		||||
+			case 100:
 | 
			
		||||
+				bmcr |= BMCR_SPEED100;
 | 
			
		||||
+				lpa |= LPA_100HALF;
 | 
			
		||||
+				break;
 | 
			
		||||
+			case 10:
 | 
			
		||||
+				lpa |= LPA_10HALF;
 | 
			
		||||
+				break;
 | 
			
		||||
+			default:
 | 
			
		||||
+				pr_warn("swphy: unknown speed\n");
 | 
			
		||||
+				return -EINVAL;
 | 
			
		||||
+			}
 | 
			
		||||
+		}
 | 
			
		||||
+
 | 
			
		||||
+		if (state->pause)
 | 
			
		||||
+			lpa |= LPA_PAUSE_CAP;
 | 
			
		||||
+
 | 
			
		||||
+		if (state->asym_pause)
 | 
			
		||||
+			lpa |= LPA_PAUSE_ASYM;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	regs[MII_PHYSID1] = 0;
 | 
			
		||||
+	regs[MII_PHYSID2] = 0;
 | 
			
		||||
+
 | 
			
		||||
+	regs[MII_BMSR] = bmsr;
 | 
			
		||||
+	regs[MII_BMCR] = bmcr;
 | 
			
		||||
+	regs[MII_LPA] = lpa;
 | 
			
		||||
+	regs[MII_STAT1000] = lpagb;
 | 
			
		||||
+
 | 
			
		||||
+	return 0;
 | 
			
		||||
+}
 | 
			
		||||
+EXPORT_SYMBOL_GPL(swphy_update_regs);
 | 
			
		||||
--- /dev/null
 | 
			
		||||
+++ b/drivers/net/phy/swphy.h
 | 
			
		||||
@@ -0,0 +1,8 @@
 | 
			
		||||
+#ifndef SWPHY_H
 | 
			
		||||
+#define SWPHY_H
 | 
			
		||||
+
 | 
			
		||||
+struct fixed_phy_status;
 | 
			
		||||
+
 | 
			
		||||
+int swphy_update_regs(u16 *regs, const struct fixed_phy_status *state);
 | 
			
		||||
+
 | 
			
		||||
+#endif
 | 
			
		||||
@@ -0,0 +1,203 @@
 | 
			
		||||
From cd834fe430f030a63bfa9277bba194e8eef4dbd0 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
Date: Sun, 20 Sep 2015 10:18:59 +0100
 | 
			
		||||
Subject: [PATCH 710/744] phy: convert swphy register generation to tabular
 | 
			
		||||
 form
 | 
			
		||||
 | 
			
		||||
Convert the swphy register generation to tabular form which allows us
 | 
			
		||||
to eliminate multiple switch() statements.  This results in a smaller
 | 
			
		||||
object code size, more efficient, and easier to add support for faster
 | 
			
		||||
speeds.
 | 
			
		||||
 | 
			
		||||
Before:
 | 
			
		||||
 | 
			
		||||
Idx Name          Size      VMA       LMA       File off  Algn
 | 
			
		||||
  0 .text         00000164  00000000  00000000  00000034  2**2
 | 
			
		||||
 | 
			
		||||
   text    data     bss     dec     hex filename
 | 
			
		||||
    388       0       0     388     184 swphy.o
 | 
			
		||||
 | 
			
		||||
After:
 | 
			
		||||
 | 
			
		||||
Idx Name          Size      VMA       LMA       File off  Algn
 | 
			
		||||
  0 .text         000000fc  00000000  00000000  00000034  2**2
 | 
			
		||||
  5 .rodata       00000028  00000000  00000000  00000138  2**2
 | 
			
		||||
 | 
			
		||||
   text    data     bss     dec     hex filename
 | 
			
		||||
    324       0       0     324     144 swphy.o
 | 
			
		||||
 | 
			
		||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
 | 
			
		||||
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
---
 | 
			
		||||
 drivers/net/phy/swphy.c | 143 ++++++++++++++++++++++++++----------------------
 | 
			
		||||
 1 file changed, 78 insertions(+), 65 deletions(-)
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/phy/swphy.c
 | 
			
		||||
+++ b/drivers/net/phy/swphy.c
 | 
			
		||||
@@ -20,6 +20,72 @@
 | 
			
		||||
 
 | 
			
		||||
 #include "swphy.h"
 | 
			
		||||
 
 | 
			
		||||
+struct swmii_regs {
 | 
			
		||||
+	u16 bmcr;
 | 
			
		||||
+	u16 bmsr;
 | 
			
		||||
+	u16 lpa;
 | 
			
		||||
+	u16 lpagb;
 | 
			
		||||
+};
 | 
			
		||||
+
 | 
			
		||||
+enum {
 | 
			
		||||
+	SWMII_SPEED_10 = 0,
 | 
			
		||||
+	SWMII_SPEED_100,
 | 
			
		||||
+	SWMII_SPEED_1000,
 | 
			
		||||
+	SWMII_DUPLEX_HALF = 0,
 | 
			
		||||
+	SWMII_DUPLEX_FULL,
 | 
			
		||||
+};
 | 
			
		||||
+
 | 
			
		||||
+/*
 | 
			
		||||
+ * These two tables get bitwise-anded together to produce the final result.
 | 
			
		||||
+ * This means the speed table must contain both duplex settings, and the
 | 
			
		||||
+ * duplex table must contain all speed settings.
 | 
			
		||||
+ */
 | 
			
		||||
+static const struct swmii_regs speed[] = {
 | 
			
		||||
+	[SWMII_SPEED_10] = {
 | 
			
		||||
+		.bmcr  = BMCR_FULLDPLX,
 | 
			
		||||
+		.lpa   = LPA_10FULL | LPA_10HALF,
 | 
			
		||||
+	},
 | 
			
		||||
+	[SWMII_SPEED_100] = {
 | 
			
		||||
+		.bmcr  = BMCR_FULLDPLX | BMCR_SPEED100,
 | 
			
		||||
+		.bmsr  = BMSR_100FULL | BMSR_100HALF,
 | 
			
		||||
+		.lpa   = LPA_100FULL | LPA_100HALF,
 | 
			
		||||
+	},
 | 
			
		||||
+	[SWMII_SPEED_1000] = {
 | 
			
		||||
+		.bmcr  = BMCR_FULLDPLX | BMCR_SPEED1000,
 | 
			
		||||
+		.bmsr  = BMSR_ESTATEN,
 | 
			
		||||
+		.lpagb = LPA_1000FULL | LPA_1000HALF,
 | 
			
		||||
+	},
 | 
			
		||||
+};
 | 
			
		||||
+
 | 
			
		||||
+static const struct swmii_regs duplex[] = {
 | 
			
		||||
+	[SWMII_DUPLEX_HALF] = {
 | 
			
		||||
+		.bmcr  = ~BMCR_FULLDPLX,
 | 
			
		||||
+		.bmsr  = BMSR_ESTATEN | BMSR_100HALF,
 | 
			
		||||
+		.lpa   = LPA_10HALF | LPA_100HALF,
 | 
			
		||||
+		.lpagb = LPA_1000HALF,
 | 
			
		||||
+	},
 | 
			
		||||
+	[SWMII_DUPLEX_FULL] = {
 | 
			
		||||
+		.bmcr  = ~0,
 | 
			
		||||
+		.bmsr  = BMSR_ESTATEN | BMSR_100FULL,
 | 
			
		||||
+		.lpa   = LPA_10FULL | LPA_100FULL,
 | 
			
		||||
+		.lpagb = LPA_1000FULL,
 | 
			
		||||
+	},
 | 
			
		||||
+};
 | 
			
		||||
+
 | 
			
		||||
+static int swphy_decode_speed(int speed)
 | 
			
		||||
+{
 | 
			
		||||
+	switch (speed) {
 | 
			
		||||
+	case 1000:
 | 
			
		||||
+		return SWMII_SPEED_1000;
 | 
			
		||||
+	case 100:
 | 
			
		||||
+		return SWMII_SPEED_100;
 | 
			
		||||
+	case 10:
 | 
			
		||||
+		return SWMII_SPEED_10;
 | 
			
		||||
+	default:
 | 
			
		||||
+		return -EINVAL;
 | 
			
		||||
+	}
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
 /**
 | 
			
		||||
  * swphy_update_regs - update MII register array with fixed phy state
 | 
			
		||||
  * @regs: array of 32 registers to update
 | 
			
		||||
@@ -30,81 +96,28 @@
 | 
			
		||||
  */
 | 
			
		||||
 int swphy_update_regs(u16 *regs, const struct fixed_phy_status *state)
 | 
			
		||||
 {
 | 
			
		||||
+	int speed_index, duplex_index;
 | 
			
		||||
 	u16 bmsr = BMSR_ANEGCAPABLE;
 | 
			
		||||
 	u16 bmcr = 0;
 | 
			
		||||
 	u16 lpagb = 0;
 | 
			
		||||
 	u16 lpa = 0;
 | 
			
		||||
 
 | 
			
		||||
-	if (state->duplex) {
 | 
			
		||||
-		switch (state->speed) {
 | 
			
		||||
-		case 1000:
 | 
			
		||||
-			bmsr |= BMSR_ESTATEN;
 | 
			
		||||
-			break;
 | 
			
		||||
-		case 100:
 | 
			
		||||
-			bmsr |= BMSR_100FULL;
 | 
			
		||||
-			break;
 | 
			
		||||
-		case 10:
 | 
			
		||||
-			bmsr |= BMSR_10FULL;
 | 
			
		||||
-			break;
 | 
			
		||||
-		default:
 | 
			
		||||
-			break;
 | 
			
		||||
-		}
 | 
			
		||||
-	} else {
 | 
			
		||||
-		switch (state->speed) {
 | 
			
		||||
-		case 1000:
 | 
			
		||||
-			bmsr |= BMSR_ESTATEN;
 | 
			
		||||
-			break;
 | 
			
		||||
-		case 100:
 | 
			
		||||
-			bmsr |= BMSR_100HALF;
 | 
			
		||||
-			break;
 | 
			
		||||
-		case 10:
 | 
			
		||||
-			bmsr |= BMSR_10HALF;
 | 
			
		||||
-			break;
 | 
			
		||||
-		default:
 | 
			
		||||
-			break;
 | 
			
		||||
-		}
 | 
			
		||||
+	speed_index = swphy_decode_speed(state->speed);
 | 
			
		||||
+	if (speed_index < 0) {
 | 
			
		||||
+		pr_warn("swphy: unknown speed\n");
 | 
			
		||||
+		return -EINVAL;
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
+	duplex_index = state->duplex ? SWMII_DUPLEX_FULL : SWMII_DUPLEX_HALF;
 | 
			
		||||
+
 | 
			
		||||
+	bmsr |= speed[speed_index].bmsr & duplex[duplex_index].bmsr;
 | 
			
		||||
+
 | 
			
		||||
 	if (state->link) {
 | 
			
		||||
 		bmsr |= BMSR_LSTATUS | BMSR_ANEGCOMPLETE;
 | 
			
		||||
 
 | 
			
		||||
-		if (state->duplex) {
 | 
			
		||||
-			bmcr |= BMCR_FULLDPLX;
 | 
			
		||||
-
 | 
			
		||||
-			switch (state->speed) {
 | 
			
		||||
-			case 1000:
 | 
			
		||||
-				bmcr |= BMCR_SPEED1000;
 | 
			
		||||
-				lpagb |= LPA_1000FULL;
 | 
			
		||||
-				break;
 | 
			
		||||
-			case 100:
 | 
			
		||||
-				bmcr |= BMCR_SPEED100;
 | 
			
		||||
-				lpa |= LPA_100FULL;
 | 
			
		||||
-				break;
 | 
			
		||||
-			case 10:
 | 
			
		||||
-				lpa |= LPA_10FULL;
 | 
			
		||||
-				break;
 | 
			
		||||
-			default:
 | 
			
		||||
-				pr_warn("swphy: unknown speed\n");
 | 
			
		||||
-				return -EINVAL;
 | 
			
		||||
-			}
 | 
			
		||||
-		} else {
 | 
			
		||||
-			switch (state->speed) {
 | 
			
		||||
-			case 1000:
 | 
			
		||||
-				bmcr |= BMCR_SPEED1000;
 | 
			
		||||
-				lpagb |= LPA_1000HALF;
 | 
			
		||||
-				break;
 | 
			
		||||
-			case 100:
 | 
			
		||||
-				bmcr |= BMCR_SPEED100;
 | 
			
		||||
-				lpa |= LPA_100HALF;
 | 
			
		||||
-				break;
 | 
			
		||||
-			case 10:
 | 
			
		||||
-				lpa |= LPA_10HALF;
 | 
			
		||||
-				break;
 | 
			
		||||
-			default:
 | 
			
		||||
-				pr_warn("swphy: unknown speed\n");
 | 
			
		||||
-				return -EINVAL;
 | 
			
		||||
-			}
 | 
			
		||||
-		}
 | 
			
		||||
+		bmcr  |= speed[speed_index].bmcr  & duplex[duplex_index].bmcr;
 | 
			
		||||
+		lpa   |= speed[speed_index].lpa   & duplex[duplex_index].lpa;
 | 
			
		||||
+		lpagb |= speed[speed_index].lpagb & duplex[duplex_index].lpagb;
 | 
			
		||||
 
 | 
			
		||||
 		if (state->pause)
 | 
			
		||||
 			lpa |= LPA_PAUSE_CAP;
 | 
			
		||||
@@ -0,0 +1,138 @@
 | 
			
		||||
From e07630ad84c7dc145863f079f108154fb7c975e7 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
Date: Sun, 20 Sep 2015 11:12:15 +0100
 | 
			
		||||
Subject: [PATCH 711/744] phy: separate swphy state validation from register
 | 
			
		||||
 generation
 | 
			
		||||
 | 
			
		||||
Separate out the generation of MII registers from the state validation.
 | 
			
		||||
This allows us to simplify the error handing in fixed_phy() by allowing
 | 
			
		||||
earlier error detection.
 | 
			
		||||
 | 
			
		||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
 | 
			
		||||
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
---
 | 
			
		||||
 drivers/net/phy/fixed_phy.c | 15 +++++++--------
 | 
			
		||||
 drivers/net/phy/swphy.c     | 33 ++++++++++++++++++++++++++-------
 | 
			
		||||
 drivers/net/phy/swphy.h     |  3 ++-
 | 
			
		||||
 3 files changed, 35 insertions(+), 16 deletions(-)
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/phy/fixed_phy.c
 | 
			
		||||
+++ b/drivers/net/phy/fixed_phy.c
 | 
			
		||||
@@ -49,12 +49,12 @@ static struct fixed_mdio_bus platform_fm
 | 
			
		||||
 	.phys = LIST_HEAD_INIT(platform_fmb.phys),
 | 
			
		||||
 };
 | 
			
		||||
 
 | 
			
		||||
-static int fixed_phy_update_regs(struct fixed_phy *fp)
 | 
			
		||||
+static void fixed_phy_update_regs(struct fixed_phy *fp)
 | 
			
		||||
 {
 | 
			
		||||
 	if (gpio_is_valid(fp->link_gpio))
 | 
			
		||||
 		fp->status.link = !!gpio_get_value_cansleep(fp->link_gpio);
 | 
			
		||||
 
 | 
			
		||||
-	return swphy_update_regs(fp->regs, &fp->status);
 | 
			
		||||
+	swphy_update_regs(fp->regs, &fp->status);
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
 static int fixed_mdio_read(struct mii_bus *bus, int phy_addr, int reg_num)
 | 
			
		||||
@@ -161,6 +161,10 @@ int fixed_phy_add(unsigned int irq, int
 | 
			
		||||
 	struct fixed_mdio_bus *fmb = &platform_fmb;
 | 
			
		||||
 	struct fixed_phy *fp;
 | 
			
		||||
 
 | 
			
		||||
+	ret = swphy_validate_state(status);
 | 
			
		||||
+	if (ret < 0)
 | 
			
		||||
+		return ret;
 | 
			
		||||
+
 | 
			
		||||
 	fp = kzalloc(sizeof(*fp), GFP_KERNEL);
 | 
			
		||||
 	if (!fp)
 | 
			
		||||
 		return -ENOMEM;
 | 
			
		||||
@@ -180,17 +184,12 @@ int fixed_phy_add(unsigned int irq, int
 | 
			
		||||
 			goto err_regs;
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
-	ret = fixed_phy_update_regs(fp);
 | 
			
		||||
-	if (ret)
 | 
			
		||||
-		goto err_gpio;
 | 
			
		||||
+	fixed_phy_update_regs(fp);
 | 
			
		||||
 
 | 
			
		||||
 	list_add_tail(&fp->node, &fmb->phys);
 | 
			
		||||
 
 | 
			
		||||
 	return 0;
 | 
			
		||||
 
 | 
			
		||||
-err_gpio:
 | 
			
		||||
-	if (gpio_is_valid(fp->link_gpio))
 | 
			
		||||
-		gpio_free(fp->link_gpio);
 | 
			
		||||
 err_regs:
 | 
			
		||||
 	kfree(fp);
 | 
			
		||||
 	return ret;
 | 
			
		||||
--- a/drivers/net/phy/swphy.c
 | 
			
		||||
+++ b/drivers/net/phy/swphy.c
 | 
			
		||||
@@ -87,6 +87,29 @@ static int swphy_decode_speed(int speed)
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
 /**
 | 
			
		||||
+ * swphy_validate_state - validate the software phy status
 | 
			
		||||
+ * @state: software phy status
 | 
			
		||||
+ *
 | 
			
		||||
+ * This checks that we can represent the state stored in @state can be
 | 
			
		||||
+ * represented in the emulated MII registers.  Returns 0 if it can,
 | 
			
		||||
+ * otherwise returns -EINVAL.
 | 
			
		||||
+ */
 | 
			
		||||
+int swphy_validate_state(const struct fixed_phy_status *state)
 | 
			
		||||
+{
 | 
			
		||||
+	int err;
 | 
			
		||||
+
 | 
			
		||||
+	if (state->link) {
 | 
			
		||||
+		err = swphy_decode_speed(state->speed);
 | 
			
		||||
+		if (err < 0) {
 | 
			
		||||
+			pr_warn("swphy: unknown speed\n");
 | 
			
		||||
+			return -EINVAL;
 | 
			
		||||
+		}
 | 
			
		||||
+	}
 | 
			
		||||
+	return 0;
 | 
			
		||||
+}
 | 
			
		||||
+EXPORT_SYMBOL_GPL(swphy_validate_state);
 | 
			
		||||
+
 | 
			
		||||
+/**
 | 
			
		||||
  * swphy_update_regs - update MII register array with fixed phy state
 | 
			
		||||
  * @regs: array of 32 registers to update
 | 
			
		||||
  * @state: fixed phy status
 | 
			
		||||
@@ -94,7 +117,7 @@ static int swphy_decode_speed(int speed)
 | 
			
		||||
  * Update the array of MII registers with the fixed phy link, speed,
 | 
			
		||||
  * duplex and pause mode settings.
 | 
			
		||||
  */
 | 
			
		||||
-int swphy_update_regs(u16 *regs, const struct fixed_phy_status *state)
 | 
			
		||||
+void swphy_update_regs(u16 *regs, const struct fixed_phy_status *state)
 | 
			
		||||
 {
 | 
			
		||||
 	int speed_index, duplex_index;
 | 
			
		||||
 	u16 bmsr = BMSR_ANEGCAPABLE;
 | 
			
		||||
@@ -103,10 +126,8 @@ int swphy_update_regs(u16 *regs, const s
 | 
			
		||||
 	u16 lpa = 0;
 | 
			
		||||
 
 | 
			
		||||
 	speed_index = swphy_decode_speed(state->speed);
 | 
			
		||||
-	if (speed_index < 0) {
 | 
			
		||||
-		pr_warn("swphy: unknown speed\n");
 | 
			
		||||
-		return -EINVAL;
 | 
			
		||||
-	}
 | 
			
		||||
+	if (WARN_ON(speed_index < 0))
 | 
			
		||||
+		return;
 | 
			
		||||
 
 | 
			
		||||
 	duplex_index = state->duplex ? SWMII_DUPLEX_FULL : SWMII_DUPLEX_HALF;
 | 
			
		||||
 
 | 
			
		||||
@@ -133,7 +154,5 @@ int swphy_update_regs(u16 *regs, const s
 | 
			
		||||
 	regs[MII_BMCR] = bmcr;
 | 
			
		||||
 	regs[MII_LPA] = lpa;
 | 
			
		||||
 	regs[MII_STAT1000] = lpagb;
 | 
			
		||||
-
 | 
			
		||||
-	return 0;
 | 
			
		||||
 }
 | 
			
		||||
 EXPORT_SYMBOL_GPL(swphy_update_regs);
 | 
			
		||||
--- a/drivers/net/phy/swphy.h
 | 
			
		||||
+++ b/drivers/net/phy/swphy.h
 | 
			
		||||
@@ -3,6 +3,7 @@
 | 
			
		||||
 
 | 
			
		||||
 struct fixed_phy_status;
 | 
			
		||||
 
 | 
			
		||||
-int swphy_update_regs(u16 *regs, const struct fixed_phy_status *state);
 | 
			
		||||
+int swphy_validate_state(const struct fixed_phy_status *state);
 | 
			
		||||
+void swphy_update_regs(u16 *regs, const struct fixed_phy_status *state);
 | 
			
		||||
 
 | 
			
		||||
 #endif
 | 
			
		||||
@@ -0,0 +1,204 @@
 | 
			
		||||
From e0f33a88243329da1aa5a90fe10ab25c9fb0a091 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
Date: Sun, 20 Sep 2015 11:28:39 +0100
 | 
			
		||||
Subject: [PATCH 712/744] phy: generate swphy registers on the fly
 | 
			
		||||
 | 
			
		||||
Generate software phy registers as and when requested, rather than
 | 
			
		||||
duplicating the state in fixed_phy.  This allows us to eliminate
 | 
			
		||||
the duplicate storage of of the same data, which is only different
 | 
			
		||||
in format.
 | 
			
		||||
 | 
			
		||||
As fixed_phy_update_regs() no longer updates register state, rename
 | 
			
		||||
it to fixed_phy_update().
 | 
			
		||||
 | 
			
		||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
 | 
			
		||||
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
---
 | 
			
		||||
 drivers/net/phy/fixed_phy.c | 31 +++++-------------------------
 | 
			
		||||
 drivers/net/phy/swphy.c     | 47 ++++++++++++++++++++++++++++++++-------------
 | 
			
		||||
 drivers/net/phy/swphy.h     |  2 +-
 | 
			
		||||
 3 files changed, 40 insertions(+), 40 deletions(-)
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/phy/fixed_phy.c
 | 
			
		||||
+++ b/drivers/net/phy/fixed_phy.c
 | 
			
		||||
@@ -26,8 +26,6 @@
 | 
			
		||||
 
 | 
			
		||||
 #include "swphy.h"
 | 
			
		||||
 
 | 
			
		||||
-#define MII_REGS_NUM 29
 | 
			
		||||
-
 | 
			
		||||
 struct fixed_mdio_bus {
 | 
			
		||||
 	int irqs[PHY_MAX_ADDR];
 | 
			
		||||
 	struct mii_bus *mii_bus;
 | 
			
		||||
@@ -36,7 +34,6 @@ struct fixed_mdio_bus {
 | 
			
		||||
 
 | 
			
		||||
 struct fixed_phy {
 | 
			
		||||
 	int addr;
 | 
			
		||||
-	u16 regs[MII_REGS_NUM];
 | 
			
		||||
 	struct phy_device *phydev;
 | 
			
		||||
 	struct fixed_phy_status status;
 | 
			
		||||
 	int (*link_update)(struct net_device *, struct fixed_phy_status *);
 | 
			
		||||
@@ -49,12 +46,10 @@ static struct fixed_mdio_bus platform_fm
 | 
			
		||||
 	.phys = LIST_HEAD_INIT(platform_fmb.phys),
 | 
			
		||||
 };
 | 
			
		||||
 
 | 
			
		||||
-static void fixed_phy_update_regs(struct fixed_phy *fp)
 | 
			
		||||
+static void fixed_phy_update(struct fixed_phy *fp)
 | 
			
		||||
 {
 | 
			
		||||
 	if (gpio_is_valid(fp->link_gpio))
 | 
			
		||||
 		fp->status.link = !!gpio_get_value_cansleep(fp->link_gpio);
 | 
			
		||||
-
 | 
			
		||||
-	swphy_update_regs(fp->regs, &fp->status);
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
 static int fixed_mdio_read(struct mii_bus *bus, int phy_addr, int reg_num)
 | 
			
		||||
@@ -62,29 +57,15 @@ static int fixed_mdio_read(struct mii_bu
 | 
			
		||||
 	struct fixed_mdio_bus *fmb = bus->priv;
 | 
			
		||||
 	struct fixed_phy *fp;
 | 
			
		||||
 
 | 
			
		||||
-	if (reg_num >= MII_REGS_NUM)
 | 
			
		||||
-		return -1;
 | 
			
		||||
-
 | 
			
		||||
-	/* We do not support emulating Clause 45 over Clause 22 register reads
 | 
			
		||||
-	 * return an error instead of bogus data.
 | 
			
		||||
-	 */
 | 
			
		||||
-	switch (reg_num) {
 | 
			
		||||
-	case MII_MMD_CTRL:
 | 
			
		||||
-	case MII_MMD_DATA:
 | 
			
		||||
-		return -1;
 | 
			
		||||
-	default:
 | 
			
		||||
-		break;
 | 
			
		||||
-	}
 | 
			
		||||
-
 | 
			
		||||
 	list_for_each_entry(fp, &fmb->phys, node) {
 | 
			
		||||
 		if (fp->addr == phy_addr) {
 | 
			
		||||
 			/* Issue callback if user registered it. */
 | 
			
		||||
 			if (fp->link_update) {
 | 
			
		||||
 				fp->link_update(fp->phydev->attached_dev,
 | 
			
		||||
 						&fp->status);
 | 
			
		||||
-				fixed_phy_update_regs(fp);
 | 
			
		||||
+				fixed_phy_update(fp);
 | 
			
		||||
 			}
 | 
			
		||||
-			return fp->regs[reg_num];
 | 
			
		||||
+			return swphy_read_reg(reg_num, &fp->status);
 | 
			
		||||
 		}
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
@@ -144,7 +125,7 @@ int fixed_phy_update_state(struct phy_de
 | 
			
		||||
 			_UPD(pause);
 | 
			
		||||
 			_UPD(asym_pause);
 | 
			
		||||
 #undef _UPD
 | 
			
		||||
-			fixed_phy_update_regs(fp);
 | 
			
		||||
+			fixed_phy_update(fp);
 | 
			
		||||
 			return 0;
 | 
			
		||||
 		}
 | 
			
		||||
 	}
 | 
			
		||||
@@ -169,8 +150,6 @@ int fixed_phy_add(unsigned int irq, int
 | 
			
		||||
 	if (!fp)
 | 
			
		||||
 		return -ENOMEM;
 | 
			
		||||
 
 | 
			
		||||
-	memset(fp->regs, 0xFF,  sizeof(fp->regs[0]) * MII_REGS_NUM);
 | 
			
		||||
-
 | 
			
		||||
 	fmb->irqs[phy_addr] = irq;
 | 
			
		||||
 
 | 
			
		||||
 	fp->addr = phy_addr;
 | 
			
		||||
@@ -184,7 +163,7 @@ int fixed_phy_add(unsigned int irq, int
 | 
			
		||||
 			goto err_regs;
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
-	fixed_phy_update_regs(fp);
 | 
			
		||||
+	fixed_phy_update(fp);
 | 
			
		||||
 
 | 
			
		||||
 	list_add_tail(&fp->node, &fmb->phys);
 | 
			
		||||
 
 | 
			
		||||
--- a/drivers/net/phy/swphy.c
 | 
			
		||||
+++ b/drivers/net/phy/swphy.c
 | 
			
		||||
@@ -20,6 +20,8 @@
 | 
			
		||||
 
 | 
			
		||||
 #include "swphy.h"
 | 
			
		||||
 
 | 
			
		||||
+#define MII_REGS_NUM 29
 | 
			
		||||
+
 | 
			
		||||
 struct swmii_regs {
 | 
			
		||||
 	u16 bmcr;
 | 
			
		||||
 	u16 bmsr;
 | 
			
		||||
@@ -110,14 +112,13 @@ int swphy_validate_state(const struct fi
 | 
			
		||||
 EXPORT_SYMBOL_GPL(swphy_validate_state);
 | 
			
		||||
 
 | 
			
		||||
 /**
 | 
			
		||||
- * swphy_update_regs - update MII register array with fixed phy state
 | 
			
		||||
- * @regs: array of 32 registers to update
 | 
			
		||||
+ * swphy_read_reg - return a MII register from the fixed phy state
 | 
			
		||||
+ * @reg: MII register
 | 
			
		||||
  * @state: fixed phy status
 | 
			
		||||
  *
 | 
			
		||||
- * Update the array of MII registers with the fixed phy link, speed,
 | 
			
		||||
- * duplex and pause mode settings.
 | 
			
		||||
+ * Return the MII @reg register generated from the fixed phy state @state.
 | 
			
		||||
  */
 | 
			
		||||
-void swphy_update_regs(u16 *regs, const struct fixed_phy_status *state)
 | 
			
		||||
+int swphy_read_reg(int reg, const struct fixed_phy_status *state)
 | 
			
		||||
 {
 | 
			
		||||
 	int speed_index, duplex_index;
 | 
			
		||||
 	u16 bmsr = BMSR_ANEGCAPABLE;
 | 
			
		||||
@@ -125,9 +126,12 @@ void swphy_update_regs(u16 *regs, const
 | 
			
		||||
 	u16 lpagb = 0;
 | 
			
		||||
 	u16 lpa = 0;
 | 
			
		||||
 
 | 
			
		||||
+	if (reg > MII_REGS_NUM)
 | 
			
		||||
+		return -1;
 | 
			
		||||
+
 | 
			
		||||
 	speed_index = swphy_decode_speed(state->speed);
 | 
			
		||||
 	if (WARN_ON(speed_index < 0))
 | 
			
		||||
-		return;
 | 
			
		||||
+		return 0;
 | 
			
		||||
 
 | 
			
		||||
 	duplex_index = state->duplex ? SWMII_DUPLEX_FULL : SWMII_DUPLEX_HALF;
 | 
			
		||||
 
 | 
			
		||||
@@ -147,12 +151,29 @@ void swphy_update_regs(u16 *regs, const
 | 
			
		||||
 			lpa |= LPA_PAUSE_ASYM;
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
-	regs[MII_PHYSID1] = 0;
 | 
			
		||||
-	regs[MII_PHYSID2] = 0;
 | 
			
		||||
+	switch (reg) {
 | 
			
		||||
+	case MII_BMCR:
 | 
			
		||||
+		return bmcr;
 | 
			
		||||
+	case MII_BMSR:
 | 
			
		||||
+		return bmsr;
 | 
			
		||||
+	case MII_PHYSID1:
 | 
			
		||||
+	case MII_PHYSID2:
 | 
			
		||||
+		return 0;
 | 
			
		||||
+	case MII_LPA:
 | 
			
		||||
+		return lpa;
 | 
			
		||||
+	case MII_STAT1000:
 | 
			
		||||
+		return lpagb;
 | 
			
		||||
+
 | 
			
		||||
+	/*
 | 
			
		||||
+	 * We do not support emulating Clause 45 over Clause 22 register
 | 
			
		||||
+	 * reads.  Return an error instead of bogus data.
 | 
			
		||||
+	 */
 | 
			
		||||
+	case MII_MMD_CTRL:
 | 
			
		||||
+	case MII_MMD_DATA:
 | 
			
		||||
+		return -1;
 | 
			
		||||
 
 | 
			
		||||
-	regs[MII_BMSR] = bmsr;
 | 
			
		||||
-	regs[MII_BMCR] = bmcr;
 | 
			
		||||
-	regs[MII_LPA] = lpa;
 | 
			
		||||
-	regs[MII_STAT1000] = lpagb;
 | 
			
		||||
+	default:
 | 
			
		||||
+		return 0xffff;
 | 
			
		||||
+	}
 | 
			
		||||
 }
 | 
			
		||||
-EXPORT_SYMBOL_GPL(swphy_update_regs);
 | 
			
		||||
+EXPORT_SYMBOL_GPL(swphy_read_reg);
 | 
			
		||||
--- a/drivers/net/phy/swphy.h
 | 
			
		||||
+++ b/drivers/net/phy/swphy.h
 | 
			
		||||
@@ -4,6 +4,6 @@
 | 
			
		||||
 struct fixed_phy_status;
 | 
			
		||||
 
 | 
			
		||||
 int swphy_validate_state(const struct fixed_phy_status *state);
 | 
			
		||||
-void swphy_update_regs(u16 *regs, const struct fixed_phy_status *state);
 | 
			
		||||
+int swphy_read_reg(int reg, const struct fixed_phy_status *state);
 | 
			
		||||
 
 | 
			
		||||
 #endif
 | 
			
		||||
@@ -0,0 +1,92 @@
 | 
			
		||||
From c36739c3cfd277a4cc9820a29dd0f4b7fbac795b Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
Date: Sun, 20 Sep 2015 18:31:36 +0100
 | 
			
		||||
Subject: [PATCH 713/744] phy: improve safety of fixed-phy MII register reading
 | 
			
		||||
 | 
			
		||||
There is no prevention of a concurrent call to both fixed_mdio_read()
 | 
			
		||||
and fixed_phy_update_state(), which can result in the state being
 | 
			
		||||
modified while it's being inspected.  Fix this by using a seqcount
 | 
			
		||||
to detect modifications, and memcpy()ing the state.
 | 
			
		||||
 | 
			
		||||
We remain slightly naughty here, calling link_update() and updating
 | 
			
		||||
the link status within the read-side loop - which would need rework
 | 
			
		||||
of the design to change.
 | 
			
		||||
 | 
			
		||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
 | 
			
		||||
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
---
 | 
			
		||||
 drivers/net/phy/fixed_phy.c | 28 +++++++++++++++++++++-------
 | 
			
		||||
 1 file changed, 21 insertions(+), 7 deletions(-)
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/phy/fixed_phy.c
 | 
			
		||||
+++ b/drivers/net/phy/fixed_phy.c
 | 
			
		||||
@@ -23,6 +23,7 @@
 | 
			
		||||
 #include <linux/slab.h>
 | 
			
		||||
 #include <linux/of.h>
 | 
			
		||||
 #include <linux/gpio.h>
 | 
			
		||||
+#include <linux/seqlock.h>
 | 
			
		||||
 
 | 
			
		||||
 #include "swphy.h"
 | 
			
		||||
 
 | 
			
		||||
@@ -35,6 +36,7 @@ struct fixed_mdio_bus {
 | 
			
		||||
 struct fixed_phy {
 | 
			
		||||
 	int addr;
 | 
			
		||||
 	struct phy_device *phydev;
 | 
			
		||||
+	seqcount_t seqcount;
 | 
			
		||||
 	struct fixed_phy_status status;
 | 
			
		||||
 	int (*link_update)(struct net_device *, struct fixed_phy_status *);
 | 
			
		||||
 	struct list_head node;
 | 
			
		||||
@@ -59,13 +61,21 @@ static int fixed_mdio_read(struct mii_bu
 | 
			
		||||
 
 | 
			
		||||
 	list_for_each_entry(fp, &fmb->phys, node) {
 | 
			
		||||
 		if (fp->addr == phy_addr) {
 | 
			
		||||
-			/* Issue callback if user registered it. */
 | 
			
		||||
-			if (fp->link_update) {
 | 
			
		||||
-				fp->link_update(fp->phydev->attached_dev,
 | 
			
		||||
-						&fp->status);
 | 
			
		||||
-				fixed_phy_update(fp);
 | 
			
		||||
-			}
 | 
			
		||||
-			return swphy_read_reg(reg_num, &fp->status);
 | 
			
		||||
+			struct fixed_phy_status state;
 | 
			
		||||
+			int s;
 | 
			
		||||
+
 | 
			
		||||
+			do {
 | 
			
		||||
+				s = read_seqcount_begin(&fp->seqcount);
 | 
			
		||||
+				/* Issue callback if user registered it. */
 | 
			
		||||
+				if (fp->link_update) {
 | 
			
		||||
+					fp->link_update(fp->phydev->attached_dev,
 | 
			
		||||
+							&fp->status);
 | 
			
		||||
+					fixed_phy_update(fp);
 | 
			
		||||
+				}
 | 
			
		||||
+				state = fp->status;
 | 
			
		||||
+			} while (read_seqcount_retry(&fp->seqcount, s));
 | 
			
		||||
+
 | 
			
		||||
+			return swphy_read_reg(reg_num, &state);
 | 
			
		||||
 		}
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
@@ -117,6 +127,7 @@ int fixed_phy_update_state(struct phy_de
 | 
			
		||||
 
 | 
			
		||||
 	list_for_each_entry(fp, &fmb->phys, node) {
 | 
			
		||||
 		if (fp->addr == phydev->addr) {
 | 
			
		||||
+			write_seqcount_begin(&fp->seqcount);
 | 
			
		||||
 #define _UPD(x) if (changed->x) \
 | 
			
		||||
 	fp->status.x = status->x
 | 
			
		||||
 			_UPD(link);
 | 
			
		||||
@@ -126,6 +137,7 @@ int fixed_phy_update_state(struct phy_de
 | 
			
		||||
 			_UPD(asym_pause);
 | 
			
		||||
 #undef _UPD
 | 
			
		||||
 			fixed_phy_update(fp);
 | 
			
		||||
+			write_seqcount_end(&fp->seqcount);
 | 
			
		||||
 			return 0;
 | 
			
		||||
 		}
 | 
			
		||||
 	}
 | 
			
		||||
@@ -150,6 +162,8 @@ int fixed_phy_add(unsigned int irq, int
 | 
			
		||||
 	if (!fp)
 | 
			
		||||
 		return -ENOMEM;
 | 
			
		||||
 
 | 
			
		||||
+	seqcount_init(&fp->seqcount);
 | 
			
		||||
+
 | 
			
		||||
 	fmb->irqs[phy_addr] = irq;
 | 
			
		||||
 
 | 
			
		||||
 	fp->addr = phy_addr;
 | 
			
		||||
@@ -0,0 +1,183 @@
 | 
			
		||||
From d8b4e728f598d3c8a9b219d4679d5de350caa082 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
Date: Fri, 18 Sep 2015 14:42:16 +0100
 | 
			
		||||
Subject: [PATCH 714/744] phy: provide a hook for link up/link down events
 | 
			
		||||
 | 
			
		||||
Sometimes, we need to do additional work between the PHY coming up and
 | 
			
		||||
marking the carrier present - for example, we may need to wait for the
 | 
			
		||||
PHY to MAC link to finish negotiation.  This changes phylib to provide
 | 
			
		||||
a notification function pointer which avoids the built-in
 | 
			
		||||
netif_carrier_on() and netif_carrier_off() functions.
 | 
			
		||||
 | 
			
		||||
Standard ->adjust_link functionality is provided by hooking a helper
 | 
			
		||||
into the new ->phy_link_change method.
 | 
			
		||||
 | 
			
		||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
 | 
			
		||||
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
---
 | 
			
		||||
 drivers/net/phy/phy.c        | 42 ++++++++++++++++++++++--------------------
 | 
			
		||||
 drivers/net/phy/phy_device.c | 14 ++++++++++++++
 | 
			
		||||
 include/linux/phy.h          |  1 +
 | 
			
		||||
 3 files changed, 37 insertions(+), 20 deletions(-)
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/phy/phy.c
 | 
			
		||||
+++ b/drivers/net/phy/phy.c
 | 
			
		||||
@@ -849,6 +849,16 @@ void phy_start(struct phy_device *phydev
 | 
			
		||||
 }
 | 
			
		||||
 EXPORT_SYMBOL(phy_start);
 | 
			
		||||
 
 | 
			
		||||
+static void phy_link_up(struct phy_device *phydev)
 | 
			
		||||
+{
 | 
			
		||||
+	phydev->phy_link_change(phydev, true, true);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static void phy_link_down(struct phy_device *phydev, bool do_carrier)
 | 
			
		||||
+{
 | 
			
		||||
+	phydev->phy_link_change(phydev, false, do_carrier);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
 /**
 | 
			
		||||
  * phy_state_machine - Handle the state machine
 | 
			
		||||
  * @work: work_struct that describes the work to be done
 | 
			
		||||
@@ -890,8 +900,7 @@ void phy_state_machine(struct work_struc
 | 
			
		||||
 		/* If the link is down, give up on negotiation for now */
 | 
			
		||||
 		if (!phydev->link) {
 | 
			
		||||
 			phydev->state = PHY_NOLINK;
 | 
			
		||||
-			netif_carrier_off(phydev->attached_dev);
 | 
			
		||||
-			phydev->adjust_link(phydev->attached_dev);
 | 
			
		||||
+			phy_link_down(phydev, true);
 | 
			
		||||
 			break;
 | 
			
		||||
 		}
 | 
			
		||||
 
 | 
			
		||||
@@ -903,9 +912,7 @@ void phy_state_machine(struct work_struc
 | 
			
		||||
 		/* If AN is done, we're running */
 | 
			
		||||
 		if (err > 0) {
 | 
			
		||||
 			phydev->state = PHY_RUNNING;
 | 
			
		||||
-			netif_carrier_on(phydev->attached_dev);
 | 
			
		||||
-			phydev->adjust_link(phydev->attached_dev);
 | 
			
		||||
-
 | 
			
		||||
+			phy_link_up(phydev);
 | 
			
		||||
 		} else if (0 == phydev->link_timeout--)
 | 
			
		||||
 			needs_aneg = true;
 | 
			
		||||
 		break;
 | 
			
		||||
@@ -930,8 +937,7 @@ void phy_state_machine(struct work_struc
 | 
			
		||||
 				}
 | 
			
		||||
 			}
 | 
			
		||||
 			phydev->state = PHY_RUNNING;
 | 
			
		||||
-			netif_carrier_on(phydev->attached_dev);
 | 
			
		||||
-			phydev->adjust_link(phydev->attached_dev);
 | 
			
		||||
+			phy_link_up(phydev);
 | 
			
		||||
 		}
 | 
			
		||||
 		break;
 | 
			
		||||
 	case PHY_FORCING:
 | 
			
		||||
@@ -941,13 +947,12 @@ void phy_state_machine(struct work_struc
 | 
			
		||||
 
 | 
			
		||||
 		if (phydev->link) {
 | 
			
		||||
 			phydev->state = PHY_RUNNING;
 | 
			
		||||
-			netif_carrier_on(phydev->attached_dev);
 | 
			
		||||
+			phy_link_up(phydev);
 | 
			
		||||
 		} else {
 | 
			
		||||
 			if (0 == phydev->link_timeout--)
 | 
			
		||||
 				needs_aneg = true;
 | 
			
		||||
+			phy_link_down(phydev, false);
 | 
			
		||||
 		}
 | 
			
		||||
-
 | 
			
		||||
-		phydev->adjust_link(phydev->attached_dev);
 | 
			
		||||
 		break;
 | 
			
		||||
 	case PHY_RUNNING:
 | 
			
		||||
 		/* Only register a CHANGE if we are polling or ignoring
 | 
			
		||||
@@ -970,14 +975,12 @@ void phy_state_machine(struct work_struc
 | 
			
		||||
 
 | 
			
		||||
 		if (phydev->link) {
 | 
			
		||||
 			phydev->state = PHY_RUNNING;
 | 
			
		||||
-			netif_carrier_on(phydev->attached_dev);
 | 
			
		||||
+			phy_link_up(phydev);
 | 
			
		||||
 		} else {
 | 
			
		||||
 			phydev->state = PHY_NOLINK;
 | 
			
		||||
-			netif_carrier_off(phydev->attached_dev);
 | 
			
		||||
+			phy_link_down(phydev, true);
 | 
			
		||||
 		}
 | 
			
		||||
 
 | 
			
		||||
-		phydev->adjust_link(phydev->attached_dev);
 | 
			
		||||
-
 | 
			
		||||
 		if (phy_interrupt_is_valid(phydev))
 | 
			
		||||
 			err = phy_config_interrupt(phydev,
 | 
			
		||||
 						   PHY_INTERRUPT_ENABLED);
 | 
			
		||||
@@ -985,8 +988,7 @@ void phy_state_machine(struct work_struc
 | 
			
		||||
 	case PHY_HALTED:
 | 
			
		||||
 		if (phydev->link) {
 | 
			
		||||
 			phydev->link = 0;
 | 
			
		||||
-			netif_carrier_off(phydev->attached_dev);
 | 
			
		||||
-			phydev->adjust_link(phydev->attached_dev);
 | 
			
		||||
+			phy_link_down(phydev, true);
 | 
			
		||||
 			do_suspend = true;
 | 
			
		||||
 		}
 | 
			
		||||
 		break;
 | 
			
		||||
@@ -1006,11 +1008,11 @@ void phy_state_machine(struct work_struc
 | 
			
		||||
 
 | 
			
		||||
 				if (phydev->link) {
 | 
			
		||||
 					phydev->state = PHY_RUNNING;
 | 
			
		||||
-					netif_carrier_on(phydev->attached_dev);
 | 
			
		||||
+					phy_link_up(phydev);
 | 
			
		||||
 				} else	{
 | 
			
		||||
 					phydev->state = PHY_NOLINK;
 | 
			
		||||
+					phy_link_down(phydev, false);
 | 
			
		||||
 				}
 | 
			
		||||
-				phydev->adjust_link(phydev->attached_dev);
 | 
			
		||||
 			} else {
 | 
			
		||||
 				phydev->state = PHY_AN;
 | 
			
		||||
 				phydev->link_timeout = PHY_AN_TIMEOUT;
 | 
			
		||||
@@ -1022,11 +1024,11 @@ void phy_state_machine(struct work_struc
 | 
			
		||||
 
 | 
			
		||||
 			if (phydev->link) {
 | 
			
		||||
 				phydev->state = PHY_RUNNING;
 | 
			
		||||
-				netif_carrier_on(phydev->attached_dev);
 | 
			
		||||
+				phy_link_up(phydev);
 | 
			
		||||
 			} else	{
 | 
			
		||||
 				phydev->state = PHY_NOLINK;
 | 
			
		||||
+				phy_link_down(phydev, false);
 | 
			
		||||
 			}
 | 
			
		||||
-			phydev->adjust_link(phydev->attached_dev);
 | 
			
		||||
 		}
 | 
			
		||||
 		break;
 | 
			
		||||
 	}
 | 
			
		||||
--- a/drivers/net/phy/phy_device.c
 | 
			
		||||
+++ b/drivers/net/phy/phy_device.c
 | 
			
		||||
@@ -441,6 +441,19 @@ struct phy_device *phy_find_first(struct
 | 
			
		||||
 }
 | 
			
		||||
 EXPORT_SYMBOL(phy_find_first);
 | 
			
		||||
 
 | 
			
		||||
+static void phy_link_change(struct phy_device *phydev, bool up, bool do_carrier)
 | 
			
		||||
+{
 | 
			
		||||
+	struct net_device *netdev = phydev->attached_dev;
 | 
			
		||||
+
 | 
			
		||||
+	if (do_carrier) {
 | 
			
		||||
+		if (up)
 | 
			
		||||
+			netif_carrier_on(netdev);
 | 
			
		||||
+		else
 | 
			
		||||
+			netif_carrier_off(netdev);
 | 
			
		||||
+	}
 | 
			
		||||
+	phydev->adjust_link(netdev);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
 /**
 | 
			
		||||
  * phy_prepare_link - prepares the PHY layer to monitor link status
 | 
			
		||||
  * @phydev: target phy_device struct
 | 
			
		||||
@@ -659,6 +672,7 @@ int phy_attach_direct(struct net_device
 | 
			
		||||
 		goto error;
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
+	phydev->phy_link_change = phy_link_change;
 | 
			
		||||
 	phydev->attached_dev = dev;
 | 
			
		||||
 	dev->phydev = phydev;
 | 
			
		||||
 
 | 
			
		||||
--- a/include/linux/phy.h
 | 
			
		||||
+++ b/include/linux/phy.h
 | 
			
		||||
@@ -433,6 +433,7 @@ struct phy_device {
 | 
			
		||||
 
 | 
			
		||||
 	u8 mdix;
 | 
			
		||||
 
 | 
			
		||||
+	void (*phy_link_change)(struct phy_device *, bool up, bool do_carrier);
 | 
			
		||||
 	void (*adjust_link)(struct net_device *dev);
 | 
			
		||||
 };
 | 
			
		||||
 #define to_phy_device(d) container_of(d, struct phy_device, dev)
 | 
			
		||||
@@ -0,0 +1,26 @@
 | 
			
		||||
From 5eed0bf3bc3e69b20a13d8ffcdf97cb720391637 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
Date: Thu, 1 Oct 2015 00:34:08 +0100
 | 
			
		||||
Subject: [PATCH 735/744] phy: marvell: 88E1512: add flow control support
 | 
			
		||||
 | 
			
		||||
The Marvell PHYs support pause frame advertisments, so we should not be
 | 
			
		||||
masking their support off.  Add the necessary flag to the Marvell PHY
 | 
			
		||||
to allow any MAC level pause frame support to be advertised.
 | 
			
		||||
 | 
			
		||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
 | 
			
		||||
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
---
 | 
			
		||||
 drivers/net/phy/marvell.c | 2 +-
 | 
			
		||||
 1 file changed, 1 insertion(+), 1 deletion(-)
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/phy/marvell.c
 | 
			
		||||
+++ b/drivers/net/phy/marvell.c
 | 
			
		||||
@@ -1142,7 +1142,7 @@ static struct phy_driver marvell_drivers
 | 
			
		||||
 		.phy_id = MARVELL_PHY_ID_88E1510,
 | 
			
		||||
 		.phy_id_mask = MARVELL_PHY_ID_MASK,
 | 
			
		||||
 		.name = "Marvell 88E1510",
 | 
			
		||||
-		.features = PHY_GBIT_FEATURES,
 | 
			
		||||
+		.features = PHY_GBIT_FEATURES | SUPPORTED_Pause,
 | 
			
		||||
 		.flags = PHY_HAS_INTERRUPT,
 | 
			
		||||
 		.config_aneg = &m88e1510_config_aneg,
 | 
			
		||||
 		.read_status = &marvell_read_status,
 | 
			
		||||
@@ -0,0 +1,25 @@
 | 
			
		||||
From f2a9687b39cda3fb67ecd5eaa88e3545e78c982c Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
Date: Fri, 16 Oct 2015 12:18:41 +0100
 | 
			
		||||
Subject: [PATCH 715/744] phy: export phy_start_machine() for phylink
 | 
			
		||||
 | 
			
		||||
phylink will need phy_start_machine exported, so lets export it as a
 | 
			
		||||
GPL symbol.  Documentation/networking/phy.txt indicates that this
 | 
			
		||||
should be a PHY API function.
 | 
			
		||||
 | 
			
		||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
 | 
			
		||||
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
---
 | 
			
		||||
 drivers/net/phy/phy.c | 1 +
 | 
			
		||||
 1 file changed, 1 insertion(+)
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/phy/phy.c
 | 
			
		||||
+++ b/drivers/net/phy/phy.c
 | 
			
		||||
@@ -568,6 +568,7 @@ void phy_start_machine(struct phy_device
 | 
			
		||||
 {
 | 
			
		||||
 	queue_delayed_work(system_power_efficient_wq, &phydev->state_queue, HZ);
 | 
			
		||||
 }
 | 
			
		||||
+EXPORT_SYMBOL_GPL(phy_start_machine);
 | 
			
		||||
 
 | 
			
		||||
 /**
 | 
			
		||||
  * phy_stop_machine - stop the PHY state machine tracking
 | 
			
		||||
@@ -0,0 +1,44 @@
 | 
			
		||||
From 5c77cc2ffd5deb4762d9551409472f2441297fe7 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
Date: Sun, 18 Oct 2015 19:51:10 +0100
 | 
			
		||||
Subject: [PATCH 716/744] phy: export phy_speed_to_str() for phylink
 | 
			
		||||
 | 
			
		||||
phylink would like to reuse phy_speed_to_str() to convert the speed
 | 
			
		||||
to a string.  Add a prototype and export this helper function.
 | 
			
		||||
 | 
			
		||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
 | 
			
		||||
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
---
 | 
			
		||||
 drivers/net/phy/phy.c | 3 ++-
 | 
			
		||||
 include/linux/phy.h   | 1 +
 | 
			
		||||
 2 files changed, 3 insertions(+), 1 deletion(-)
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/phy/phy.c
 | 
			
		||||
+++ b/drivers/net/phy/phy.c
 | 
			
		||||
@@ -38,7 +38,7 @@
 | 
			
		||||
 
 | 
			
		||||
 #include <asm/irq.h>
 | 
			
		||||
 
 | 
			
		||||
-static const char *phy_speed_to_str(int speed)
 | 
			
		||||
+const char *phy_speed_to_str(int speed)
 | 
			
		||||
 {
 | 
			
		||||
 	switch (speed) {
 | 
			
		||||
 	case SPEED_10:
 | 
			
		||||
@@ -57,6 +57,7 @@ static const char *phy_speed_to_str(int
 | 
			
		||||
 		return "Unsupported (update phy.c)";
 | 
			
		||||
 	}
 | 
			
		||||
 }
 | 
			
		||||
+EXPORT_SYMBOL_GPL(phy_speed_to_str);
 | 
			
		||||
 
 | 
			
		||||
 #define PHY_STATE_STR(_state)			\
 | 
			
		||||
 	case PHY_##_state:			\
 | 
			
		||||
--- a/include/linux/phy.h
 | 
			
		||||
+++ b/include/linux/phy.h
 | 
			
		||||
@@ -812,6 +812,7 @@ int phy_ethtool_gset(struct phy_device *
 | 
			
		||||
 int phy_ethtool_ioctl(struct phy_device *phydev, void *useraddr);
 | 
			
		||||
 int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd);
 | 
			
		||||
 int phy_start_interrupts(struct phy_device *phydev);
 | 
			
		||||
+const char *phy_speed_to_str(int speed);
 | 
			
		||||
 void phy_print_status(struct phy_device *phydev);
 | 
			
		||||
 void phy_device_free(struct phy_device *phydev);
 | 
			
		||||
 int phy_set_max_speed(struct phy_device *phydev, u32 max_speed);
 | 
			
		||||
							
								
								
									
										163
									
								
								target/linux/mvebu/patches-4.4/129-phy-add-I2C-mdio-bus.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										163
									
								
								target/linux/mvebu/patches-4.4/129-phy-add-I2C-mdio-bus.patch
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,163 @@
 | 
			
		||||
From 7f36ac946bfbd4090b8b94be3661b41ac73e21f4 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
Date: Fri, 25 Sep 2015 17:43:52 +0100
 | 
			
		||||
Subject: [PATCH 717/744] phy: add I2C mdio bus
 | 
			
		||||
 | 
			
		||||
Add an I2C MDIO bus bridge library, to allow phylib to access PHYs which
 | 
			
		||||
are connected to an I2C bus instead of the more conventional MDIO bus.
 | 
			
		||||
Such PHYs can be found in SFP adapters and SFF modules.
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
---
 | 
			
		||||
 drivers/net/phy/Kconfig    | 10 ++++++
 | 
			
		||||
 drivers/net/phy/Makefile   |  1 +
 | 
			
		||||
 drivers/net/phy/mdio-i2c.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++
 | 
			
		||||
 drivers/net/phy/mdio-i2c.h | 19 ++++++++++
 | 
			
		||||
 4 files changed, 120 insertions(+)
 | 
			
		||||
 create mode 100644 drivers/net/phy/mdio-i2c.c
 | 
			
		||||
 create mode 100644 drivers/net/phy/mdio-i2c.h
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/phy/Kconfig
 | 
			
		||||
+++ b/drivers/net/phy/Kconfig
 | 
			
		||||
@@ -233,6 +233,16 @@ config MDIO_GPIO
 | 
			
		||||
 	  To compile this driver as a module, choose M here: the module
 | 
			
		||||
 	  will be called mdio-gpio.
 | 
			
		||||
 
 | 
			
		||||
+config MDIO_I2C
 | 
			
		||||
+	tristate
 | 
			
		||||
+	depends on I2C
 | 
			
		||||
+	help
 | 
			
		||||
+	  Support I2C based PHYs.  This provides a MDIO bus bridged
 | 
			
		||||
+	  to I2C to allow PHYs connected in I2C mode to be accessed
 | 
			
		||||
+	  using the existing infrastructure.
 | 
			
		||||
+
 | 
			
		||||
+	  This is library mode.
 | 
			
		||||
+
 | 
			
		||||
 config MDIO_OCTEON
 | 
			
		||||
 	tristate "Support for MDIO buses on Octeon and ThunderX SOCs"
 | 
			
		||||
 	depends on 64BIT
 | 
			
		||||
--- a/drivers/net/phy/Makefile
 | 
			
		||||
+++ b/drivers/net/phy/Makefile
 | 
			
		||||
@@ -41,6 +41,7 @@ obj-$(CONFIG_SWCONFIG_B53)	+= b53/
 | 
			
		||||
 obj-$(CONFIG_FIXED_PHY)		+= fixed_phy.o
 | 
			
		||||
 obj-$(CONFIG_MDIO_BITBANG)	+= mdio-bitbang.o
 | 
			
		||||
 obj-$(CONFIG_MDIO_GPIO)		+= mdio-gpio.o
 | 
			
		||||
+obj-$(CONFIG_MDIO_I2C)		+= mdio-i2c.o
 | 
			
		||||
 obj-$(CONFIG_NATIONAL_PHY)	+= national.o
 | 
			
		||||
 obj-$(CONFIG_DP83640_PHY)	+= dp83640.o
 | 
			
		||||
 obj-$(CONFIG_DP83848_PHY)	+= dp83848.o
 | 
			
		||||
--- /dev/null
 | 
			
		||||
+++ b/drivers/net/phy/mdio-i2c.c
 | 
			
		||||
@@ -0,0 +1,90 @@
 | 
			
		||||
+/*
 | 
			
		||||
+ * MDIO I2C bridge
 | 
			
		||||
+ *
 | 
			
		||||
+ * Copyright (C) 2015 Russell King
 | 
			
		||||
+ *
 | 
			
		||||
+ * 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/i2c.h>
 | 
			
		||||
+#include <linux/phy.h>
 | 
			
		||||
+
 | 
			
		||||
+#include "mdio-i2c.h"
 | 
			
		||||
+
 | 
			
		||||
+static int i2c_mii_read(struct mii_bus *bus, int phy_id, int reg)
 | 
			
		||||
+{
 | 
			
		||||
+	struct i2c_adapter *i2c = bus->priv;
 | 
			
		||||
+	struct i2c_msg msgs[2];
 | 
			
		||||
+	u8 data[2], dev_addr = reg;
 | 
			
		||||
+	int bus_addr, ret;
 | 
			
		||||
+
 | 
			
		||||
+	bus_addr = 0x40 + phy_id;
 | 
			
		||||
+	if (bus_addr == 0x50 || bus_addr == 0x51)
 | 
			
		||||
+		return 0xffff;
 | 
			
		||||
+
 | 
			
		||||
+	msgs[0].addr = bus_addr;
 | 
			
		||||
+	msgs[0].flags = 0;
 | 
			
		||||
+	msgs[0].len = 1;
 | 
			
		||||
+	msgs[0].buf = &dev_addr;
 | 
			
		||||
+	msgs[1].addr = bus_addr;
 | 
			
		||||
+	msgs[1].flags = I2C_M_RD;
 | 
			
		||||
+	msgs[1].len = sizeof(data);
 | 
			
		||||
+	msgs[1].buf = data;
 | 
			
		||||
+
 | 
			
		||||
+	ret = i2c_transfer(i2c, msgs, ARRAY_SIZE(msgs));
 | 
			
		||||
+	if (ret != ARRAY_SIZE(msgs))
 | 
			
		||||
+		return 0xffff;
 | 
			
		||||
+
 | 
			
		||||
+	return data[0] << 8 | data[1];
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static int i2c_mii_write(struct mii_bus *bus, int phy_id, int reg, u16 val)
 | 
			
		||||
+{
 | 
			
		||||
+	struct i2c_adapter *i2c = bus->priv;
 | 
			
		||||
+	struct i2c_msg msg;
 | 
			
		||||
+	int bus_addr, ret;
 | 
			
		||||
+	u8 data[3];
 | 
			
		||||
+
 | 
			
		||||
+	bus_addr = 0x40 + phy_id;
 | 
			
		||||
+	if (bus_addr == 0x50 || bus_addr == 0x51)
 | 
			
		||||
+		return 0;
 | 
			
		||||
+
 | 
			
		||||
+	data[0] = reg;
 | 
			
		||||
+	data[1] = val >> 8;
 | 
			
		||||
+	data[2] = val;
 | 
			
		||||
+
 | 
			
		||||
+	msg.addr = bus_addr;
 | 
			
		||||
+	msg.flags = 0;
 | 
			
		||||
+	msg.len = 3;
 | 
			
		||||
+	msg.buf = data;
 | 
			
		||||
+
 | 
			
		||||
+	ret = i2c_transfer(i2c, &msg, 1);
 | 
			
		||||
+
 | 
			
		||||
+	return ret < 0 ? ret : 0;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c)
 | 
			
		||||
+{
 | 
			
		||||
+	struct mii_bus *mii;
 | 
			
		||||
+
 | 
			
		||||
+	if (!i2c_check_functionality(i2c, I2C_FUNC_I2C))
 | 
			
		||||
+		return ERR_PTR(-EINVAL);
 | 
			
		||||
+
 | 
			
		||||
+	mii = mdiobus_alloc();
 | 
			
		||||
+	if (!mii)
 | 
			
		||||
+		return ERR_PTR(-ENOMEM);
 | 
			
		||||
+
 | 
			
		||||
+	snprintf(mii->id, MII_BUS_ID_SIZE, "i2c:%s", dev_name(parent));
 | 
			
		||||
+	mii->parent = parent;
 | 
			
		||||
+	mii->read = i2c_mii_read;
 | 
			
		||||
+	mii->write = i2c_mii_write;
 | 
			
		||||
+	mii->priv = i2c;
 | 
			
		||||
+
 | 
			
		||||
+	return mii;
 | 
			
		||||
+}
 | 
			
		||||
+EXPORT_SYMBOL_GPL(mdio_i2c_alloc);
 | 
			
		||||
+
 | 
			
		||||
+MODULE_AUTHOR("Russell King");
 | 
			
		||||
+MODULE_DESCRIPTION("MDIO I2C bridge library");
 | 
			
		||||
+MODULE_LICENSE("GPL v2");
 | 
			
		||||
--- /dev/null
 | 
			
		||||
+++ b/drivers/net/phy/mdio-i2c.h
 | 
			
		||||
@@ -0,0 +1,19 @@
 | 
			
		||||
+/*
 | 
			
		||||
+ * MDIO I2C bridge
 | 
			
		||||
+ *
 | 
			
		||||
+ * Copyright (C) 2015 Russell King
 | 
			
		||||
+ *
 | 
			
		||||
+ * 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.
 | 
			
		||||
+ */
 | 
			
		||||
+#ifndef MDIO_I2C_H
 | 
			
		||||
+#define MDIO_I2C_H
 | 
			
		||||
+
 | 
			
		||||
+struct device;
 | 
			
		||||
+struct i2c_adapter;
 | 
			
		||||
+struct mii_bus;
 | 
			
		||||
+
 | 
			
		||||
+struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c);
 | 
			
		||||
+
 | 
			
		||||
+#endif
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -0,0 +1,156 @@
 | 
			
		||||
From 0a0c4b3dd4f34df4532f254a5940b520015d766f Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
Date: Thu, 24 Sep 2015 11:01:13 +0100
 | 
			
		||||
Subject: [PATCH 719/744] phylink: add hooks for SFP support
 | 
			
		||||
 | 
			
		||||
Add support to phylink for SFP, which needs to control and configure
 | 
			
		||||
the ethernet MAC link state.  Specifically, SFP needs to:
 | 
			
		||||
 | 
			
		||||
1. set the negotiation mode between SGMII and 1000base-X
 | 
			
		||||
2. attach and detach the module PHY
 | 
			
		||||
3. prevent the link coming up when errors are reported
 | 
			
		||||
 | 
			
		||||
In the absence of a PHY, we also need to set the ethtool port type
 | 
			
		||||
according to the module plugged in.
 | 
			
		||||
 | 
			
		||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
 | 
			
		||||
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
---
 | 
			
		||||
 drivers/net/phy/phylink.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++
 | 
			
		||||
 include/linux/phylink.h   |  6 ++++
 | 
			
		||||
 2 files changed, 88 insertions(+)
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/phy/phylink.c
 | 
			
		||||
+++ b/drivers/net/phy/phylink.c
 | 
			
		||||
@@ -11,6 +11,7 @@
 | 
			
		||||
 #include <linux/ethtool.h>
 | 
			
		||||
 #include <linux/export.h>
 | 
			
		||||
 #include <linux/gpio/consumer.h>
 | 
			
		||||
+#include <linux/list.h>
 | 
			
		||||
 #include <linux/netdevice.h>
 | 
			
		||||
 #include <linux/of.h>
 | 
			
		||||
 #include <linux/of_mdio.h>
 | 
			
		||||
@@ -29,11 +30,16 @@
 | 
			
		||||
 	(ADVERTISED_TP | ADVERTISED_MII | ADVERTISED_FIBRE | \
 | 
			
		||||
 	 ADVERTISED_BNC | ADVERTISED_AUI | ADVERTISED_Backplane)
 | 
			
		||||
 
 | 
			
		||||
+static LIST_HEAD(phylinks);
 | 
			
		||||
+static DEFINE_MUTEX(phylink_mutex);
 | 
			
		||||
+
 | 
			
		||||
 enum {
 | 
			
		||||
 	PHYLINK_DISABLE_STOPPED,
 | 
			
		||||
+	PHYLINK_DISABLE_LINK,
 | 
			
		||||
 };
 | 
			
		||||
 
 | 
			
		||||
 struct phylink {
 | 
			
		||||
+	struct list_head node;
 | 
			
		||||
 	struct net_device *netdev;
 | 
			
		||||
 	const struct phylink_mac_ops *ops;
 | 
			
		||||
 	struct mutex config_mutex;
 | 
			
		||||
@@ -341,12 +347,20 @@ struct phylink *phylink_create(struct ne
 | 
			
		||||
 		return ERR_PTR(ret);
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
+	mutex_lock(&phylink_mutex);
 | 
			
		||||
+	list_add_tail(&pl->node, &phylinks);
 | 
			
		||||
+	mutex_unlock(&phylink_mutex);
 | 
			
		||||
+
 | 
			
		||||
 	return pl;
 | 
			
		||||
 }
 | 
			
		||||
 EXPORT_SYMBOL_GPL(phylink_create);
 | 
			
		||||
 
 | 
			
		||||
 void phylink_destroy(struct phylink *pl)
 | 
			
		||||
 {
 | 
			
		||||
+	mutex_lock(&phylink_mutex);
 | 
			
		||||
+	list_del(&pl->node);
 | 
			
		||||
+	mutex_unlock(&phylink_mutex);
 | 
			
		||||
+
 | 
			
		||||
 	cancel_work_sync(&pl->resolve);
 | 
			
		||||
 	kfree(pl);
 | 
			
		||||
 }
 | 
			
		||||
@@ -813,4 +827,72 @@ int phylink_mii_ioctl(struct phylink *pl
 | 
			
		||||
 }
 | 
			
		||||
 EXPORT_SYMBOL_GPL(phylink_mii_ioctl);
 | 
			
		||||
 
 | 
			
		||||
+
 | 
			
		||||
+
 | 
			
		||||
+void phylink_disable(struct phylink *pl)
 | 
			
		||||
+{
 | 
			
		||||
+	set_bit(PHYLINK_DISABLE_LINK, &pl->phylink_disable_state);
 | 
			
		||||
+	flush_work(&pl->resolve);
 | 
			
		||||
+
 | 
			
		||||
+	netif_carrier_off(pl->netdev);
 | 
			
		||||
+}
 | 
			
		||||
+EXPORT_SYMBOL_GPL(phylink_disable);
 | 
			
		||||
+
 | 
			
		||||
+void phylink_enable(struct phylink *pl)
 | 
			
		||||
+{
 | 
			
		||||
+	clear_bit(PHYLINK_DISABLE_LINK, &pl->phylink_disable_state);
 | 
			
		||||
+	phylink_run_resolve(pl);
 | 
			
		||||
+}
 | 
			
		||||
+EXPORT_SYMBOL_GPL(phylink_enable);
 | 
			
		||||
+
 | 
			
		||||
+void phylink_set_link_port(struct phylink *pl, u32 support, u8 port)
 | 
			
		||||
+{
 | 
			
		||||
+	WARN_ON(support & ~SUPPORTED_INTERFACES);
 | 
			
		||||
+
 | 
			
		||||
+	mutex_lock(&pl->config_mutex);
 | 
			
		||||
+	pl->link_port_support = support;
 | 
			
		||||
+	pl->link_port = port;
 | 
			
		||||
+	mutex_unlock(&pl->config_mutex);
 | 
			
		||||
+}
 | 
			
		||||
+EXPORT_SYMBOL_GPL(phylink_set_link_port);
 | 
			
		||||
+
 | 
			
		||||
+int phylink_set_link_an_mode(struct phylink *pl, unsigned int mode)
 | 
			
		||||
+{
 | 
			
		||||
+	int ret = 0;
 | 
			
		||||
+
 | 
			
		||||
+	mutex_lock(&pl->config_mutex);
 | 
			
		||||
+	if (pl->link_an_mode != mode) {
 | 
			
		||||
+		ret = phylink_get_support(pl, mode);
 | 
			
		||||
+		if (ret == 0) {
 | 
			
		||||
+			if (!test_bit(PHYLINK_DISABLE_STOPPED,
 | 
			
		||||
+				      &pl->phylink_disable_state))
 | 
			
		||||
+				phylink_mac_config(pl, &pl->link_config);
 | 
			
		||||
+
 | 
			
		||||
+			netdev_info(pl->netdev, "switched to %s link mode\n",
 | 
			
		||||
+				    phylink_an_mode_str(mode));
 | 
			
		||||
+		}
 | 
			
		||||
+	}
 | 
			
		||||
+	mutex_unlock(&pl->config_mutex);
 | 
			
		||||
+
 | 
			
		||||
+	return ret;
 | 
			
		||||
+}
 | 
			
		||||
+EXPORT_SYMBOL_GPL(phylink_set_link_an_mode);
 | 
			
		||||
+
 | 
			
		||||
+struct phylink *phylink_lookup_by_netdev(struct net_device *ndev)
 | 
			
		||||
+{
 | 
			
		||||
+	struct phylink *pl, *found = NULL;
 | 
			
		||||
+
 | 
			
		||||
+	mutex_lock(&phylink_mutex);
 | 
			
		||||
+	list_for_each_entry(pl, &phylinks, node)
 | 
			
		||||
+		if (pl->netdev == ndev) {
 | 
			
		||||
+			found = pl;
 | 
			
		||||
+			break;
 | 
			
		||||
+		}
 | 
			
		||||
+
 | 
			
		||||
+	mutex_unlock(&phylink_mutex);
 | 
			
		||||
+
 | 
			
		||||
+	return found;
 | 
			
		||||
+}
 | 
			
		||||
+EXPORT_SYMBOL_GPL(phylink_lookup_by_netdev);
 | 
			
		||||
+
 | 
			
		||||
 MODULE_LICENSE("GPL");
 | 
			
		||||
--- a/include/linux/phylink.h
 | 
			
		||||
+++ b/include/linux/phylink.h
 | 
			
		||||
@@ -67,4 +67,10 @@ int phylink_ethtool_get_settings(struct
 | 
			
		||||
 int phylink_ethtool_set_settings(struct phylink *, struct ethtool_cmd *);
 | 
			
		||||
 int phylink_mii_ioctl(struct phylink *, struct ifreq *, int);
 | 
			
		||||
 
 | 
			
		||||
+void phylink_set_link_port(struct phylink *pl, u32 support, u8 port);
 | 
			
		||||
+int phylink_set_link_an_mode(struct phylink *pl, unsigned int mode);
 | 
			
		||||
+void phylink_disable(struct phylink *pl);
 | 
			
		||||
+void phylink_enable(struct phylink *pl);
 | 
			
		||||
+struct phylink *phylink_lookup_by_netdev(struct net_device *ndev);
 | 
			
		||||
+
 | 
			
		||||
 #endif
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -0,0 +1,283 @@
 | 
			
		||||
From 66c248886538d7ee97ef2fe498061f857d4c906a Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
Date: Sun, 13 Sep 2015 01:06:31 +0100
 | 
			
		||||
Subject: [PATCH 721/744] sfp: display SFP module information
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
---
 | 
			
		||||
 drivers/net/phy/sfp.c | 247 +++++++++++++++++++++++++++++++++++++++++++++++++-
 | 
			
		||||
 1 file changed, 246 insertions(+), 1 deletion(-)
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/phy/sfp.c
 | 
			
		||||
+++ b/drivers/net/phy/sfp.c
 | 
			
		||||
@@ -248,6 +248,182 @@ static unsigned int sfp_check(void *buf,
 | 
			
		||||
 	return check;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
+static const char *sfp_link_len(char *buf, size_t size, unsigned int length,
 | 
			
		||||
+	unsigned int multiplier)
 | 
			
		||||
+{
 | 
			
		||||
+	if (length == 0)
 | 
			
		||||
+		return "unsupported/unspecified";
 | 
			
		||||
+
 | 
			
		||||
+	if (length == 255) {
 | 
			
		||||
+		*buf++ = '>';
 | 
			
		||||
+		size -= 1;
 | 
			
		||||
+		length -= 1;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	length *= multiplier;
 | 
			
		||||
+
 | 
			
		||||
+	if (length >= 1000)
 | 
			
		||||
+		snprintf(buf, size, "%u.%0*ukm",
 | 
			
		||||
+			length / 1000,
 | 
			
		||||
+			multiplier > 100 ? 1 :
 | 
			
		||||
+			multiplier > 10 ? 2 : 3,
 | 
			
		||||
+			length % 1000);
 | 
			
		||||
+	else
 | 
			
		||||
+		snprintf(buf, size, "%um", length);
 | 
			
		||||
+
 | 
			
		||||
+	return buf;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+struct bitfield {
 | 
			
		||||
+	unsigned int mask;
 | 
			
		||||
+	unsigned int val;
 | 
			
		||||
+	const char *str;
 | 
			
		||||
+};
 | 
			
		||||
+
 | 
			
		||||
+static const struct bitfield sfp_options[] = {
 | 
			
		||||
+	{
 | 
			
		||||
+		.mask = SFP_OPTIONS_HIGH_POWER_LEVEL,
 | 
			
		||||
+		.val = SFP_OPTIONS_HIGH_POWER_LEVEL,
 | 
			
		||||
+		.str = "hpl",
 | 
			
		||||
+	}, {
 | 
			
		||||
+		.mask = SFP_OPTIONS_PAGING_A2,
 | 
			
		||||
+		.val = SFP_OPTIONS_PAGING_A2,
 | 
			
		||||
+		.str = "paginga2",
 | 
			
		||||
+	}, {
 | 
			
		||||
+		.mask = SFP_OPTIONS_RETIMER,
 | 
			
		||||
+		.val = SFP_OPTIONS_RETIMER,
 | 
			
		||||
+		.str = "retimer",
 | 
			
		||||
+	}, {
 | 
			
		||||
+		.mask = SFP_OPTIONS_COOLED_XCVR,
 | 
			
		||||
+		.val = SFP_OPTIONS_COOLED_XCVR,
 | 
			
		||||
+		.str = "cooled",
 | 
			
		||||
+	}, {
 | 
			
		||||
+		.mask = SFP_OPTIONS_POWER_DECL,
 | 
			
		||||
+		.val = SFP_OPTIONS_POWER_DECL,
 | 
			
		||||
+		.str = "powerdecl",
 | 
			
		||||
+	}, {
 | 
			
		||||
+		.mask = SFP_OPTIONS_RX_LINEAR_OUT,
 | 
			
		||||
+		.val = SFP_OPTIONS_RX_LINEAR_OUT,
 | 
			
		||||
+		.str = "rxlinear",
 | 
			
		||||
+	}, {
 | 
			
		||||
+		.mask = SFP_OPTIONS_RX_DECISION_THRESH,
 | 
			
		||||
+		.val = SFP_OPTIONS_RX_DECISION_THRESH,
 | 
			
		||||
+		.str = "rxthresh",
 | 
			
		||||
+	}, {
 | 
			
		||||
+		.mask = SFP_OPTIONS_TUNABLE_TX,
 | 
			
		||||
+		.val = SFP_OPTIONS_TUNABLE_TX,
 | 
			
		||||
+		.str = "tunabletx",
 | 
			
		||||
+	}, {
 | 
			
		||||
+		.mask = SFP_OPTIONS_RATE_SELECT,
 | 
			
		||||
+		.val = SFP_OPTIONS_RATE_SELECT,
 | 
			
		||||
+		.str = "ratesel",
 | 
			
		||||
+	}, {
 | 
			
		||||
+		.mask = SFP_OPTIONS_TX_DISABLE,
 | 
			
		||||
+		.val = SFP_OPTIONS_TX_DISABLE,
 | 
			
		||||
+		.str = "txdisable",
 | 
			
		||||
+	}, {
 | 
			
		||||
+		.mask = SFP_OPTIONS_TX_FAULT,
 | 
			
		||||
+		.val = SFP_OPTIONS_TX_FAULT,
 | 
			
		||||
+		.str = "txfault",
 | 
			
		||||
+	}, {
 | 
			
		||||
+		.mask = SFP_OPTIONS_LOS_INVERTED,
 | 
			
		||||
+		.val = SFP_OPTIONS_LOS_INVERTED,
 | 
			
		||||
+		.str = "los-",
 | 
			
		||||
+	}, {
 | 
			
		||||
+		.mask = SFP_OPTIONS_LOS_NORMAL,
 | 
			
		||||
+		.val = SFP_OPTIONS_LOS_NORMAL,
 | 
			
		||||
+		.str = "los+",
 | 
			
		||||
+	}, { }
 | 
			
		||||
+};
 | 
			
		||||
+
 | 
			
		||||
+static const struct bitfield diagmon[] = {
 | 
			
		||||
+	{
 | 
			
		||||
+		.mask = SFP_DIAGMON_DDM,
 | 
			
		||||
+		.val = SFP_DIAGMON_DDM,
 | 
			
		||||
+		.str = "ddm",
 | 
			
		||||
+	}, {
 | 
			
		||||
+		.mask = SFP_DIAGMON_INT_CAL,
 | 
			
		||||
+		.val = SFP_DIAGMON_INT_CAL,
 | 
			
		||||
+		.str = "intcal",
 | 
			
		||||
+	}, {
 | 
			
		||||
+		.mask = SFP_DIAGMON_EXT_CAL,
 | 
			
		||||
+		.val = SFP_DIAGMON_EXT_CAL,
 | 
			
		||||
+		.str = "extcal",
 | 
			
		||||
+	}, {
 | 
			
		||||
+		.mask = SFP_DIAGMON_RXPWR_AVG,
 | 
			
		||||
+		.val = SFP_DIAGMON_RXPWR_AVG,
 | 
			
		||||
+		.str = "rxpwravg",
 | 
			
		||||
+	}, { }
 | 
			
		||||
+};
 | 
			
		||||
+
 | 
			
		||||
+static const char *sfp_bitfield(char *out, size_t outsz, const struct bitfield *bits, unsigned int val)
 | 
			
		||||
+{
 | 
			
		||||
+	char *p = out;
 | 
			
		||||
+	int n;
 | 
			
		||||
+
 | 
			
		||||
+	*p = '\0';
 | 
			
		||||
+	while (bits->mask) {
 | 
			
		||||
+		if ((val & bits->mask) == bits->val) {
 | 
			
		||||
+			n = snprintf(p, outsz, "%s%s",
 | 
			
		||||
+				     out != p ? ", " : "",
 | 
			
		||||
+				     bits->str);
 | 
			
		||||
+			if (n == outsz)
 | 
			
		||||
+				break;
 | 
			
		||||
+			p += n;
 | 
			
		||||
+			outsz -= n;
 | 
			
		||||
+		}
 | 
			
		||||
+		bits++;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	return out;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static const char *sfp_connector(unsigned int connector)
 | 
			
		||||
+{
 | 
			
		||||
+	switch (connector) {
 | 
			
		||||
+	case SFP_CONNECTOR_UNSPEC:
 | 
			
		||||
+		return "unknown/unspecified";
 | 
			
		||||
+	case SFP_CONNECTOR_SC:
 | 
			
		||||
+		return "SC";
 | 
			
		||||
+	case SFP_CONNECTOR_FIBERJACK:
 | 
			
		||||
+		return "Fiberjack";
 | 
			
		||||
+	case SFP_CONNECTOR_LC:
 | 
			
		||||
+		return "LC";
 | 
			
		||||
+	case SFP_CONNECTOR_MT_RJ:
 | 
			
		||||
+		return "MT-RJ";
 | 
			
		||||
+	case SFP_CONNECTOR_MU:
 | 
			
		||||
+		return "MU";
 | 
			
		||||
+	case SFP_CONNECTOR_SG:
 | 
			
		||||
+		return "SG";
 | 
			
		||||
+	case SFP_CONNECTOR_OPTICAL_PIGTAIL:
 | 
			
		||||
+		return "Optical pigtail";
 | 
			
		||||
+	case SFP_CONNECTOR_HSSDC_II:
 | 
			
		||||
+		return "HSSDC II";
 | 
			
		||||
+	case SFP_CONNECTOR_COPPER_PIGTAIL:
 | 
			
		||||
+		return "Copper pigtail";
 | 
			
		||||
+	default:
 | 
			
		||||
+		return "unknown";
 | 
			
		||||
+	}
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static const char *sfp_encoding(unsigned int encoding)
 | 
			
		||||
+{
 | 
			
		||||
+	switch (encoding) {
 | 
			
		||||
+	case SFP_ENCODING_UNSPEC:
 | 
			
		||||
+		return "unspecified";
 | 
			
		||||
+	case SFP_ENCODING_8B10B:
 | 
			
		||||
+		return "8b10b";
 | 
			
		||||
+	case SFP_ENCODING_4B5B:
 | 
			
		||||
+		return "4b5b";
 | 
			
		||||
+	case SFP_ENCODING_NRZ:
 | 
			
		||||
+		return "NRZ";
 | 
			
		||||
+	case SFP_ENCODING_MANCHESTER:
 | 
			
		||||
+		return "MANCHESTER";
 | 
			
		||||
+	default:
 | 
			
		||||
+		return "unknown";
 | 
			
		||||
+	}
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
 /* Helpers */
 | 
			
		||||
 static void sfp_module_tx_disable(struct sfp *sfp)
 | 
			
		||||
 {
 | 
			
		||||
@@ -426,6 +602,7 @@ static int sfp_sm_mod_probe(struct sfp *
 | 
			
		||||
 	char sn[17];
 | 
			
		||||
 	char date[9];
 | 
			
		||||
 	char rev[5];
 | 
			
		||||
+	char options[80];
 | 
			
		||||
 	u8 check;
 | 
			
		||||
 	int err;
 | 
			
		||||
 
 | 
			
		||||
@@ -462,10 +639,78 @@ static int sfp_sm_mod_probe(struct sfp *
 | 
			
		||||
 	rev[4] = '\0';
 | 
			
		||||
 	memcpy(sn, sfp->id.ext.vendor_sn, 16);
 | 
			
		||||
 	sn[16] = '\0';
 | 
			
		||||
-	memcpy(date, sfp->id.ext.datecode, 8);
 | 
			
		||||
+	date[0] = sfp->id.ext.datecode[4];
 | 
			
		||||
+	date[1] = sfp->id.ext.datecode[5];
 | 
			
		||||
+	date[2] = '-';
 | 
			
		||||
+	date[3] = sfp->id.ext.datecode[2];
 | 
			
		||||
+	date[4] = sfp->id.ext.datecode[3];
 | 
			
		||||
+	date[5] = '-';
 | 
			
		||||
+	date[6] = sfp->id.ext.datecode[0];
 | 
			
		||||
+	date[7] = sfp->id.ext.datecode[1];
 | 
			
		||||
 	date[8] = '\0';
 | 
			
		||||
 
 | 
			
		||||
 	dev_info(sfp->dev, "module %s %s rev %s sn %s dc %s\n", vendor, part, rev, sn, date);
 | 
			
		||||
+	dev_info(sfp->dev, "  %s connector, encoding %s, nominal bitrate %u.%uGbps +%u%% -%u%%\n",
 | 
			
		||||
+		 sfp_connector(sfp->id.base.connector),
 | 
			
		||||
+		 sfp_encoding(sfp->id.base.encoding),
 | 
			
		||||
+		 sfp->id.base.br_nominal / 10,
 | 
			
		||||
+		 sfp->id.base.br_nominal % 10,
 | 
			
		||||
+		 sfp->id.ext.br_max, sfp->id.ext.br_min);
 | 
			
		||||
+	dev_info(sfp->dev, "  1000BaseSX%c 1000BaseLX%c 1000BaseCX%c 1000BaseT%c 100BaseTLX%c 1000BaseFX%c BaseBX10%c BasePX%c\n",
 | 
			
		||||
+		 sfp->id.base.e1000_base_sx ? '+' : '-',
 | 
			
		||||
+		 sfp->id.base.e1000_base_lx ? '+' : '-',
 | 
			
		||||
+		 sfp->id.base.e1000_base_cx ? '+' : '-',
 | 
			
		||||
+		 sfp->id.base.e1000_base_t ? '+' : '-',
 | 
			
		||||
+		 sfp->id.base.e100_base_lx ? '+' : '-',
 | 
			
		||||
+		 sfp->id.base.e100_base_fx ? '+' : '-',
 | 
			
		||||
+		 sfp->id.base.e_base_bx10 ? '+' : '-',
 | 
			
		||||
+		 sfp->id.base.e_base_px ? '+' : '-');
 | 
			
		||||
+
 | 
			
		||||
+	if (!sfp->id.base.sfp_ct_passive && !sfp->id.base.sfp_ct_active &&
 | 
			
		||||
+	    !sfp->id.base.e1000_base_t) {
 | 
			
		||||
+		char len_9um[16], len_om[16];
 | 
			
		||||
+
 | 
			
		||||
+		dev_info(sfp->dev, "  Wavelength %unm, fiber lengths:\n",
 | 
			
		||||
+			 be16_to_cpup(&sfp->id.base.optical_wavelength));
 | 
			
		||||
+
 | 
			
		||||
+		if (sfp->id.base.link_len[0] == 255)
 | 
			
		||||
+			strcpy(len_9um, ">254km");
 | 
			
		||||
+		else if (sfp->id.base.link_len[1] && sfp->id.base.link_len[1] != 255)
 | 
			
		||||
+			sprintf(len_9um, "%um",
 | 
			
		||||
+				sfp->id.base.link_len[1] * 100);
 | 
			
		||||
+		else if (sfp->id.base.link_len[0])
 | 
			
		||||
+			sprintf(len_9um, "%ukm", sfp->id.base.link_len[0]);
 | 
			
		||||
+		else if (sfp->id.base.link_len[1] == 255)
 | 
			
		||||
+			strcpy(len_9um, ">25.4km");
 | 
			
		||||
+		else
 | 
			
		||||
+			strcpy(len_9um, "unsupported");
 | 
			
		||||
+
 | 
			
		||||
+		dev_info(sfp->dev, "    9µm SM    : %s\n", len_9um);
 | 
			
		||||
+		dev_info(sfp->dev, " 62.5µm MM OM1: %s\n",
 | 
			
		||||
+			 sfp_link_len(len_om, sizeof(len_om),
 | 
			
		||||
+				      sfp->id.base.link_len[3], 10));
 | 
			
		||||
+		dev_info(sfp->dev, "   50µm MM OM2: %s\n",
 | 
			
		||||
+			 sfp_link_len(len_om, sizeof(len_om),
 | 
			
		||||
+				      sfp->id.base.link_len[2], 10));
 | 
			
		||||
+		dev_info(sfp->dev, "   50µm MM OM3: %s\n",
 | 
			
		||||
+			 sfp_link_len(len_om, sizeof(len_om),
 | 
			
		||||
+				      sfp->id.base.link_len[5], 10));
 | 
			
		||||
+		dev_info(sfp->dev, "   50µm MM OM4: %s\n",
 | 
			
		||||
+			 sfp_link_len(len_om, sizeof(len_om),
 | 
			
		||||
+				      sfp->id.base.link_len[4], 10));
 | 
			
		||||
+	} else {
 | 
			
		||||
+		char len[16];
 | 
			
		||||
+		dev_info(sfp->dev, "  Copper length: %s\n",
 | 
			
		||||
+			 sfp_link_len(len, sizeof(len),
 | 
			
		||||
+				      sfp->id.base.link_len[4], 1));
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	dev_info(sfp->dev, "  Options: %s\n",
 | 
			
		||||
+		 sfp_bitfield(options, sizeof(options), sfp_options,
 | 
			
		||||
+			      be16_to_cpu(sfp->id.ext.options)));
 | 
			
		||||
+	dev_info(sfp->dev, "  Diagnostics: %s\n",
 | 
			
		||||
+		 sfp_bitfield(options, sizeof(options), diagmon,
 | 
			
		||||
+			      sfp->id.ext.diagmon));
 | 
			
		||||
 
 | 
			
		||||
 	/* We only support SFP modules, not the legacy GBIC modules. */
 | 
			
		||||
 	if (sfp->id.base.phys_id != SFP_PHYS_ID_SFP ||
 | 
			
		||||
@@ -0,0 +1,697 @@
 | 
			
		||||
From e268be0ddc666f4a98db462cbed2a97637e82b5c Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
Date: Wed, 16 Sep 2015 21:27:10 +0100
 | 
			
		||||
Subject: [PATCH 722/744] net: mvneta: convert to phylink
 | 
			
		||||
 | 
			
		||||
Convert mvneta to use phylink, which models the MAC to PHY link in
 | 
			
		||||
a generic, reusable form.
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
---
 | 
			
		||||
 drivers/net/ethernet/marvell/Kconfig  |   2 +-
 | 
			
		||||
 drivers/net/ethernet/marvell/mvneta.c | 451 +++++++++++++++++-----------------
 | 
			
		||||
 2 files changed, 227 insertions(+), 226 deletions(-)
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/ethernet/marvell/Kconfig
 | 
			
		||||
+++ b/drivers/net/ethernet/marvell/Kconfig
 | 
			
		||||
@@ -58,7 +58,7 @@ config MVNETA
 | 
			
		||||
 	tristate "Marvell Armada 370/38x/XP network interface support"
 | 
			
		||||
 	depends on PLAT_ORION
 | 
			
		||||
 	select MVMDIO
 | 
			
		||||
-	select FIXED_PHY
 | 
			
		||||
+	select PHYLINK
 | 
			
		||||
 	---help---
 | 
			
		||||
 	  This driver supports the network interface units in the
 | 
			
		||||
 	  Marvell ARMADA XP, ARMADA 370 and ARMADA 38x SoC family.
 | 
			
		||||
--- a/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
+++ b/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
@@ -28,6 +28,7 @@
 | 
			
		||||
 #include <linux/of_mdio.h>
 | 
			
		||||
 #include <linux/of_net.h>
 | 
			
		||||
 #include <linux/phy.h>
 | 
			
		||||
+#include <linux/phylink.h>
 | 
			
		||||
 #include <linux/platform_device.h>
 | 
			
		||||
 #include <linux/skbuff.h>
 | 
			
		||||
 #include <net/hwbm.h>
 | 
			
		||||
@@ -188,6 +189,7 @@
 | 
			
		||||
 #define MVNETA_GMAC_CTRL_0                       0x2c00
 | 
			
		||||
 #define      MVNETA_GMAC_MAX_RX_SIZE_SHIFT       2
 | 
			
		||||
 #define      MVNETA_GMAC_MAX_RX_SIZE_MASK        0x7ffc
 | 
			
		||||
+#define      MVNETA_GMAC0_PORT_1000BASE_X        BIT(1)
 | 
			
		||||
 #define      MVNETA_GMAC0_PORT_ENABLE            BIT(0)
 | 
			
		||||
 #define MVNETA_GMAC_CTRL_2                       0x2c08
 | 
			
		||||
 #define      MVNETA_GMAC2_INBAND_AN_ENABLE       BIT(0)
 | 
			
		||||
@@ -203,13 +205,19 @@
 | 
			
		||||
 #define      MVNETA_GMAC_TX_FLOW_CTRL_ENABLE     BIT(5)
 | 
			
		||||
 #define      MVNETA_GMAC_RX_FLOW_CTRL_ACTIVE     BIT(6)
 | 
			
		||||
 #define      MVNETA_GMAC_TX_FLOW_CTRL_ACTIVE     BIT(7)
 | 
			
		||||
+#define      MVNETA_GMAC_AN_COMPLETE             BIT(11)
 | 
			
		||||
+#define      MVNETA_GMAC_SYNC_OK                 BIT(14)
 | 
			
		||||
 #define MVNETA_GMAC_AUTONEG_CONFIG               0x2c0c
 | 
			
		||||
 #define      MVNETA_GMAC_FORCE_LINK_DOWN         BIT(0)
 | 
			
		||||
 #define      MVNETA_GMAC_FORCE_LINK_PASS         BIT(1)
 | 
			
		||||
 #define      MVNETA_GMAC_INBAND_AN_ENABLE        BIT(2)
 | 
			
		||||
+#define      MVNETA_GMAC_AN_BYPASS_ENABLE        BIT(3)
 | 
			
		||||
+#define      MVNETA_GMAC_INBAND_RESTART_AN       BIT(4)
 | 
			
		||||
 #define      MVNETA_GMAC_CONFIG_MII_SPEED        BIT(5)
 | 
			
		||||
 #define      MVNETA_GMAC_CONFIG_GMII_SPEED       BIT(6)
 | 
			
		||||
 #define      MVNETA_GMAC_AN_SPEED_EN             BIT(7)
 | 
			
		||||
+#define      MVNETA_GMAC_CONFIG_FLOW_CTRL        BIT(8)
 | 
			
		||||
+#define      MVNETA_GMAC_ADVERT_SYM_FLOW_CTRL    BIT(9)
 | 
			
		||||
 #define      MVNETA_GMAC_AN_FLOW_CTRL_EN         BIT(11)
 | 
			
		||||
 #define      MVNETA_GMAC_CONFIG_FULL_DUPLEX      BIT(12)
 | 
			
		||||
 #define      MVNETA_GMAC_AN_DUPLEX_EN            BIT(13)
 | 
			
		||||
@@ -396,15 +404,9 @@ struct mvneta_port {
 | 
			
		||||
 	u16 tx_ring_size;
 | 
			
		||||
 	u16 rx_ring_size;
 | 
			
		||||
 
 | 
			
		||||
-	struct mii_bus *mii_bus;
 | 
			
		||||
-	struct phy_device *phy_dev;
 | 
			
		||||
-	phy_interface_t phy_interface;
 | 
			
		||||
-	struct device_node *phy_node;
 | 
			
		||||
-	unsigned int link;
 | 
			
		||||
-	unsigned int duplex;
 | 
			
		||||
-	unsigned int speed;
 | 
			
		||||
+	struct device_node *dn;
 | 
			
		||||
 	unsigned int tx_csum_limit;
 | 
			
		||||
-	unsigned int use_inband_status:1;
 | 
			
		||||
+	struct phylink *phylink;
 | 
			
		||||
 
 | 
			
		||||
 	struct mvneta_bm *bm_priv;
 | 
			
		||||
 	struct mvneta_bm_pool *pool_long;
 | 
			
		||||
@@ -1236,44 +1238,6 @@ static void mvneta_set_other_mcast_table
 | 
			
		||||
 		mvreg_write(pp, MVNETA_DA_FILT_OTH_MCAST + offset, val);
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
-static void mvneta_set_autoneg(struct mvneta_port *pp, int enable)
 | 
			
		||||
-{
 | 
			
		||||
-	u32 val;
 | 
			
		||||
-
 | 
			
		||||
-	if (enable) {
 | 
			
		||||
-		val = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG);
 | 
			
		||||
-		val &= ~(MVNETA_GMAC_FORCE_LINK_PASS |
 | 
			
		||||
-			 MVNETA_GMAC_FORCE_LINK_DOWN |
 | 
			
		||||
-			 MVNETA_GMAC_AN_FLOW_CTRL_EN);
 | 
			
		||||
-		val |= MVNETA_GMAC_INBAND_AN_ENABLE |
 | 
			
		||||
-		       MVNETA_GMAC_AN_SPEED_EN |
 | 
			
		||||
-		       MVNETA_GMAC_AN_DUPLEX_EN;
 | 
			
		||||
-		mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val);
 | 
			
		||||
-
 | 
			
		||||
-		val = mvreg_read(pp, MVNETA_GMAC_CLOCK_DIVIDER);
 | 
			
		||||
-		val |= MVNETA_GMAC_1MS_CLOCK_ENABLE;
 | 
			
		||||
-		mvreg_write(pp, MVNETA_GMAC_CLOCK_DIVIDER, val);
 | 
			
		||||
-
 | 
			
		||||
-		val = mvreg_read(pp, MVNETA_GMAC_CTRL_2);
 | 
			
		||||
-		val |= MVNETA_GMAC2_INBAND_AN_ENABLE;
 | 
			
		||||
-		mvreg_write(pp, MVNETA_GMAC_CTRL_2, val);
 | 
			
		||||
-	} else {
 | 
			
		||||
-		val = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG);
 | 
			
		||||
-		val &= ~(MVNETA_GMAC_INBAND_AN_ENABLE |
 | 
			
		||||
-		       MVNETA_GMAC_AN_SPEED_EN |
 | 
			
		||||
-		       MVNETA_GMAC_AN_DUPLEX_EN);
 | 
			
		||||
-		mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val);
 | 
			
		||||
-
 | 
			
		||||
-		val = mvreg_read(pp, MVNETA_GMAC_CLOCK_DIVIDER);
 | 
			
		||||
-		val &= ~MVNETA_GMAC_1MS_CLOCK_ENABLE;
 | 
			
		||||
-		mvreg_write(pp, MVNETA_GMAC_CLOCK_DIVIDER, val);
 | 
			
		||||
-
 | 
			
		||||
-		val = mvreg_read(pp, MVNETA_GMAC_CTRL_2);
 | 
			
		||||
-		val &= ~MVNETA_GMAC2_INBAND_AN_ENABLE;
 | 
			
		||||
-		mvreg_write(pp, MVNETA_GMAC_CTRL_2, val);
 | 
			
		||||
-	}
 | 
			
		||||
-}
 | 
			
		||||
-
 | 
			
		||||
 static void mvneta_percpu_unmask_interrupt(void *arg)
 | 
			
		||||
 {
 | 
			
		||||
 	struct mvneta_port *pp = arg;
 | 
			
		||||
@@ -1421,7 +1385,6 @@ static void mvneta_defaults_set(struct m
 | 
			
		||||
 	val &= ~MVNETA_PHY_POLLING_ENABLE;
 | 
			
		||||
 	mvreg_write(pp, MVNETA_UNIT_CONTROL, val);
 | 
			
		||||
 
 | 
			
		||||
-	mvneta_set_autoneg(pp, pp->use_inband_status);
 | 
			
		||||
 	mvneta_set_ucast_table(pp, -1);
 | 
			
		||||
 	mvneta_set_special_mcast_table(pp, -1);
 | 
			
		||||
 	mvneta_set_other_mcast_table(pp, -1);
 | 
			
		||||
@@ -2614,26 +2577,11 @@ static irqreturn_t mvneta_isr(int irq, v
 | 
			
		||||
 	return IRQ_HANDLED;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
-static int mvneta_fixed_link_update(struct mvneta_port *pp,
 | 
			
		||||
-				    struct phy_device *phy)
 | 
			
		||||
+static void mvneta_link_change(struct mvneta_port *pp)
 | 
			
		||||
 {
 | 
			
		||||
-	struct fixed_phy_status status;
 | 
			
		||||
-	struct fixed_phy_status changed = {};
 | 
			
		||||
 	u32 gmac_stat = mvreg_read(pp, MVNETA_GMAC_STATUS);
 | 
			
		||||
 
 | 
			
		||||
-	status.link = !!(gmac_stat & MVNETA_GMAC_LINK_UP);
 | 
			
		||||
-	if (gmac_stat & MVNETA_GMAC_SPEED_1000)
 | 
			
		||||
-		status.speed = SPEED_1000;
 | 
			
		||||
-	else if (gmac_stat & MVNETA_GMAC_SPEED_100)
 | 
			
		||||
-		status.speed = SPEED_100;
 | 
			
		||||
-	else
 | 
			
		||||
-		status.speed = SPEED_10;
 | 
			
		||||
-	status.duplex = !!(gmac_stat & MVNETA_GMAC_FULL_DUPLEX);
 | 
			
		||||
-	changed.link = 1;
 | 
			
		||||
-	changed.speed = 1;
 | 
			
		||||
-	changed.duplex = 1;
 | 
			
		||||
-	fixed_phy_update_state(phy, &status, &changed);
 | 
			
		||||
-	return 0;
 | 
			
		||||
+	phylink_mac_change(pp->phylink, !!(gmac_stat & MVNETA_GMAC_LINK_UP));
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
 /* NAPI handler
 | 
			
		||||
@@ -2662,12 +2610,11 @@ static int mvneta_poll(struct napi_struc
 | 
			
		||||
 		u32 cause_misc = mvreg_read(pp, MVNETA_INTR_MISC_CAUSE);
 | 
			
		||||
 
 | 
			
		||||
 		mvreg_write(pp, MVNETA_INTR_MISC_CAUSE, 0);
 | 
			
		||||
-		if (pp->use_inband_status && (cause_misc &
 | 
			
		||||
-				(MVNETA_CAUSE_PHY_STATUS_CHANGE |
 | 
			
		||||
-				 MVNETA_CAUSE_LINK_CHANGE |
 | 
			
		||||
-				 MVNETA_CAUSE_PSC_SYNC_CHANGE))) {
 | 
			
		||||
-			mvneta_fixed_link_update(pp, pp->phy_dev);
 | 
			
		||||
-		}
 | 
			
		||||
+
 | 
			
		||||
+		if (cause_misc & (MVNETA_CAUSE_PHY_STATUS_CHANGE |
 | 
			
		||||
+				  MVNETA_CAUSE_LINK_CHANGE |
 | 
			
		||||
+				  MVNETA_CAUSE_PSC_SYNC_CHANGE))
 | 
			
		||||
+			mvneta_link_change(pp);
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
 	/* Release Tx descriptors */
 | 
			
		||||
@@ -2983,7 +2930,7 @@ static void mvneta_start_dev(struct mvne
 | 
			
		||||
 		    MVNETA_CAUSE_LINK_CHANGE |
 | 
			
		||||
 		    MVNETA_CAUSE_PSC_SYNC_CHANGE);
 | 
			
		||||
 
 | 
			
		||||
-	phy_start(pp->phy_dev);
 | 
			
		||||
+	phylink_start(pp->phylink);
 | 
			
		||||
 	netif_tx_start_all_queues(pp->dev);
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
@@ -2991,7 +2938,7 @@ static void mvneta_stop_dev(struct mvnet
 | 
			
		||||
 {
 | 
			
		||||
 	unsigned int cpu;
 | 
			
		||||
 
 | 
			
		||||
-	phy_stop(pp->phy_dev);
 | 
			
		||||
+	phylink_stop(pp->phylink);
 | 
			
		||||
 
 | 
			
		||||
 	for_each_online_cpu(cpu) {
 | 
			
		||||
 		struct mvneta_pcpu_port *port = per_cpu_ptr(pp->ports, cpu);
 | 
			
		||||
@@ -3161,99 +3108,219 @@ static int mvneta_set_mac_addr(struct ne
 | 
			
		||||
 	return 0;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
-static void mvneta_adjust_link(struct net_device *ndev)
 | 
			
		||||
+static int mvneta_mac_support(struct net_device *ndev, unsigned int mode,
 | 
			
		||||
+			      struct phylink_link_state *state)
 | 
			
		||||
+{
 | 
			
		||||
+	switch (mode) {
 | 
			
		||||
+	case MLO_AN_8023Z:
 | 
			
		||||
+		state->supported = SUPPORTED_1000baseT_Full |
 | 
			
		||||
+				   SUPPORTED_Autoneg | SUPPORTED_Pause;
 | 
			
		||||
+		state->advertising = ADVERTISED_1000baseT_Full |
 | 
			
		||||
+				     ADVERTISED_Autoneg | ADVERTISED_Pause;
 | 
			
		||||
+		state->an_enabled = 1;
 | 
			
		||||
+		break;
 | 
			
		||||
+
 | 
			
		||||
+	case MLO_AN_FIXED:
 | 
			
		||||
+		break;
 | 
			
		||||
+
 | 
			
		||||
+	default:
 | 
			
		||||
+		state->supported = PHY_10BT_FEATURES |
 | 
			
		||||
+				   PHY_100BT_FEATURES |
 | 
			
		||||
+				   SUPPORTED_1000baseT_Full |
 | 
			
		||||
+				   SUPPORTED_Autoneg;
 | 
			
		||||
+		state->advertising = ADVERTISED_10baseT_Half |
 | 
			
		||||
+				     ADVERTISED_10baseT_Full |
 | 
			
		||||
+				     ADVERTISED_100baseT_Half |
 | 
			
		||||
+				     ADVERTISED_100baseT_Full |
 | 
			
		||||
+				     ADVERTISED_1000baseT_Full |
 | 
			
		||||
+				     ADVERTISED_Autoneg;
 | 
			
		||||
+		state->an_enabled = 1;
 | 
			
		||||
+		break;
 | 
			
		||||
+	}
 | 
			
		||||
+	return 0;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static int mvneta_mac_link_state(struct net_device *ndev,
 | 
			
		||||
+				 struct phylink_link_state *state)
 | 
			
		||||
 {
 | 
			
		||||
 	struct mvneta_port *pp = netdev_priv(ndev);
 | 
			
		||||
-	struct phy_device *phydev = pp->phy_dev;
 | 
			
		||||
-	int status_change = 0;
 | 
			
		||||
+	u32 gmac_stat;
 | 
			
		||||
 
 | 
			
		||||
-	if (phydev->link) {
 | 
			
		||||
-		if ((pp->speed != phydev->speed) ||
 | 
			
		||||
-		    (pp->duplex != phydev->duplex)) {
 | 
			
		||||
-			u32 val;
 | 
			
		||||
-
 | 
			
		||||
-			val = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG);
 | 
			
		||||
-			val &= ~(MVNETA_GMAC_CONFIG_MII_SPEED |
 | 
			
		||||
-				 MVNETA_GMAC_CONFIG_GMII_SPEED |
 | 
			
		||||
-				 MVNETA_GMAC_CONFIG_FULL_DUPLEX);
 | 
			
		||||
-
 | 
			
		||||
-			if (phydev->duplex)
 | 
			
		||||
-				val |= MVNETA_GMAC_CONFIG_FULL_DUPLEX;
 | 
			
		||||
-
 | 
			
		||||
-			if (phydev->speed == SPEED_1000)
 | 
			
		||||
-				val |= MVNETA_GMAC_CONFIG_GMII_SPEED;
 | 
			
		||||
-			else if (phydev->speed == SPEED_100)
 | 
			
		||||
-				val |= MVNETA_GMAC_CONFIG_MII_SPEED;
 | 
			
		||||
+	gmac_stat = mvreg_read(pp, MVNETA_GMAC_STATUS);
 | 
			
		||||
 
 | 
			
		||||
-			mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val);
 | 
			
		||||
+	if (gmac_stat & MVNETA_GMAC_SPEED_1000)
 | 
			
		||||
+		state->speed = SPEED_1000;
 | 
			
		||||
+	else if (gmac_stat & MVNETA_GMAC_SPEED_100)
 | 
			
		||||
+		state->speed = SPEED_100;
 | 
			
		||||
+	else
 | 
			
		||||
+		state->speed = SPEED_10;
 | 
			
		||||
 
 | 
			
		||||
-			pp->duplex = phydev->duplex;
 | 
			
		||||
-			pp->speed  = phydev->speed;
 | 
			
		||||
-		}
 | 
			
		||||
+	state->an_complete = !!(gmac_stat & MVNETA_GMAC_AN_COMPLETE);
 | 
			
		||||
+	state->sync = !!(gmac_stat & MVNETA_GMAC_SYNC_OK);
 | 
			
		||||
+	state->link = !!(gmac_stat & MVNETA_GMAC_LINK_UP);
 | 
			
		||||
+	state->duplex = !!(gmac_stat & MVNETA_GMAC_FULL_DUPLEX);
 | 
			
		||||
+
 | 
			
		||||
+	state->pause = 0;
 | 
			
		||||
+	if (gmac_stat & MVNETA_GMAC_RX_FLOW_CTRL_ENABLE)
 | 
			
		||||
+		state->pause |= MLO_PAUSE_RX;
 | 
			
		||||
+	if (gmac_stat & MVNETA_GMAC_TX_FLOW_CTRL_ENABLE)
 | 
			
		||||
+		state->pause |= MLO_PAUSE_TX;
 | 
			
		||||
+
 | 
			
		||||
+	return 1;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static void mvneta_mac_an_restart(struct net_device *ndev, unsigned int mode)
 | 
			
		||||
+{
 | 
			
		||||
+	struct mvneta_port *pp = netdev_priv(ndev);
 | 
			
		||||
+
 | 
			
		||||
+	if (mode == MLO_AN_8023Z) {
 | 
			
		||||
+		u32 gmac_an = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG);
 | 
			
		||||
+
 | 
			
		||||
+		mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG,
 | 
			
		||||
+			    gmac_an | MVNETA_GMAC_INBAND_RESTART_AN);
 | 
			
		||||
+		mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG,
 | 
			
		||||
+			    gmac_an & ~MVNETA_GMAC_INBAND_RESTART_AN);
 | 
			
		||||
 	}
 | 
			
		||||
+}
 | 
			
		||||
 
 | 
			
		||||
-	if (phydev->link != pp->link) {
 | 
			
		||||
-		if (!phydev->link) {
 | 
			
		||||
-			pp->duplex = -1;
 | 
			
		||||
-			pp->speed = 0;
 | 
			
		||||
-		}
 | 
			
		||||
+static void mvneta_mac_config(struct net_device *ndev, unsigned int mode,
 | 
			
		||||
+	const struct phylink_link_state *state)
 | 
			
		||||
+{
 | 
			
		||||
+	struct mvneta_port *pp = netdev_priv(ndev);
 | 
			
		||||
+	u32 new_ctrl0, gmac_ctrl0 = mvreg_read(pp, MVNETA_GMAC_CTRL_0);
 | 
			
		||||
+	u32 new_ctrl2, gmac_ctrl2 = mvreg_read(pp, MVNETA_GMAC_CTRL_2);
 | 
			
		||||
+	u32 new_clk, gmac_clk = mvreg_read(pp, MVNETA_GMAC_CLOCK_DIVIDER);
 | 
			
		||||
+	u32 new_an, gmac_an = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG);
 | 
			
		||||
+
 | 
			
		||||
+	new_ctrl0 = gmac_ctrl0 & ~MVNETA_GMAC0_PORT_1000BASE_X;
 | 
			
		||||
+	new_ctrl2 = gmac_ctrl2 & ~MVNETA_GMAC2_INBAND_AN_ENABLE;
 | 
			
		||||
+	new_clk = gmac_clk & ~MVNETA_GMAC_1MS_CLOCK_ENABLE;
 | 
			
		||||
+	new_an = gmac_an & ~(MVNETA_GMAC_INBAND_AN_ENABLE |
 | 
			
		||||
+			     MVNETA_GMAC_INBAND_RESTART_AN |
 | 
			
		||||
+			     MVNETA_GMAC_CONFIG_MII_SPEED |
 | 
			
		||||
+			     MVNETA_GMAC_CONFIG_GMII_SPEED |
 | 
			
		||||
+			     MVNETA_GMAC_AN_SPEED_EN |
 | 
			
		||||
+			     MVNETA_GMAC_ADVERT_SYM_FLOW_CTRL |
 | 
			
		||||
+			     MVNETA_GMAC_CONFIG_FLOW_CTRL |
 | 
			
		||||
+			     MVNETA_GMAC_AN_FLOW_CTRL_EN |
 | 
			
		||||
+			     MVNETA_GMAC_CONFIG_FULL_DUPLEX |
 | 
			
		||||
+			     MVNETA_GMAC_AN_DUPLEX_EN);
 | 
			
		||||
+
 | 
			
		||||
+	if (state->advertising & ADVERTISED_Pause)
 | 
			
		||||
+		new_an |= MVNETA_GMAC_ADVERT_SYM_FLOW_CTRL;
 | 
			
		||||
+
 | 
			
		||||
+	switch (mode) {
 | 
			
		||||
+	case MLO_AN_SGMII:
 | 
			
		||||
+		/* SGMII mode receives the state from the PHY */
 | 
			
		||||
+		new_ctrl2 |= MVNETA_GMAC2_INBAND_AN_ENABLE;
 | 
			
		||||
+		new_clk |= MVNETA_GMAC_1MS_CLOCK_ENABLE;
 | 
			
		||||
+		new_an = (new_an & ~(MVNETA_GMAC_FORCE_LINK_DOWN |
 | 
			
		||||
+				     MVNETA_GMAC_FORCE_LINK_PASS)) |
 | 
			
		||||
+			 MVNETA_GMAC_INBAND_AN_ENABLE |
 | 
			
		||||
+			 MVNETA_GMAC_AN_SPEED_EN |
 | 
			
		||||
+			 MVNETA_GMAC_AN_DUPLEX_EN;
 | 
			
		||||
+		break;
 | 
			
		||||
+
 | 
			
		||||
+	case MLO_AN_8023Z:
 | 
			
		||||
+		/* 802.3z negotiation - only 1000base-X */
 | 
			
		||||
+		new_ctrl0 |= MVNETA_GMAC0_PORT_1000BASE_X;
 | 
			
		||||
+		new_clk |= MVNETA_GMAC_1MS_CLOCK_ENABLE;
 | 
			
		||||
+		new_an = (new_an & ~(MVNETA_GMAC_FORCE_LINK_DOWN |
 | 
			
		||||
+				     MVNETA_GMAC_FORCE_LINK_PASS)) |
 | 
			
		||||
+			 MVNETA_GMAC_INBAND_AN_ENABLE |
 | 
			
		||||
+			 MVNETA_GMAC_CONFIG_GMII_SPEED |
 | 
			
		||||
+			 /* The MAC only supports FD mode */
 | 
			
		||||
+			 MVNETA_GMAC_CONFIG_FULL_DUPLEX;
 | 
			
		||||
+
 | 
			
		||||
+		if (state->an_enabled)
 | 
			
		||||
+			new_an |= MVNETA_GMAC_AN_FLOW_CTRL_EN;
 | 
			
		||||
+		break;
 | 
			
		||||
 
 | 
			
		||||
-		pp->link = phydev->link;
 | 
			
		||||
-		status_change = 1;
 | 
			
		||||
+	default:
 | 
			
		||||
+		/* Phy or fixed speed */
 | 
			
		||||
+		if (state->duplex)
 | 
			
		||||
+			new_an |= MVNETA_GMAC_CONFIG_FULL_DUPLEX;
 | 
			
		||||
+
 | 
			
		||||
+		if (state->speed == SPEED_1000)
 | 
			
		||||
+			new_an |= MVNETA_GMAC_CONFIG_GMII_SPEED;
 | 
			
		||||
+		else if (state->speed == SPEED_100)
 | 
			
		||||
+			new_an |= MVNETA_GMAC_CONFIG_MII_SPEED;
 | 
			
		||||
+		break;
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
-	if (status_change) {
 | 
			
		||||
-		if (phydev->link) {
 | 
			
		||||
-			if (!pp->use_inband_status) {
 | 
			
		||||
-				u32 val = mvreg_read(pp,
 | 
			
		||||
-						  MVNETA_GMAC_AUTONEG_CONFIG);
 | 
			
		||||
-				val &= ~MVNETA_GMAC_FORCE_LINK_DOWN;
 | 
			
		||||
-				val |= MVNETA_GMAC_FORCE_LINK_PASS;
 | 
			
		||||
-				mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG,
 | 
			
		||||
-					    val);
 | 
			
		||||
-			}
 | 
			
		||||
-			mvneta_port_up(pp);
 | 
			
		||||
-		} else {
 | 
			
		||||
-			if (!pp->use_inband_status) {
 | 
			
		||||
-				u32 val = mvreg_read(pp,
 | 
			
		||||
-						  MVNETA_GMAC_AUTONEG_CONFIG);
 | 
			
		||||
-				val &= ~MVNETA_GMAC_FORCE_LINK_PASS;
 | 
			
		||||
-				val |= MVNETA_GMAC_FORCE_LINK_DOWN;
 | 
			
		||||
-				mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG,
 | 
			
		||||
-					    val);
 | 
			
		||||
-			}
 | 
			
		||||
-			mvneta_port_down(pp);
 | 
			
		||||
-		}
 | 
			
		||||
-		phy_print_status(phydev);
 | 
			
		||||
+	/* Armada 370 documentation says we can only change the port mode
 | 
			
		||||
+	 * and in-band enable when the link is down, so force it down
 | 
			
		||||
+	 * while making these changes. We also do this for GMAC_CTRL2 */
 | 
			
		||||
+	if ((new_ctrl0 ^ gmac_ctrl0) & MVNETA_GMAC0_PORT_1000BASE_X ||
 | 
			
		||||
+	    (new_ctrl2 ^ gmac_ctrl2) & MVNETA_GMAC2_INBAND_AN_ENABLE ||
 | 
			
		||||
+	    (new_an  ^ gmac_an) & MVNETA_GMAC_INBAND_AN_ENABLE) {
 | 
			
		||||
+		mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG,
 | 
			
		||||
+			    (gmac_an & ~MVNETA_GMAC_FORCE_LINK_PASS) |
 | 
			
		||||
+			    MVNETA_GMAC_FORCE_LINK_DOWN);
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	if (new_ctrl0 != gmac_ctrl0)
 | 
			
		||||
+		mvreg_write(pp, MVNETA_GMAC_CTRL_0, new_ctrl0);
 | 
			
		||||
+	if (new_ctrl2 != gmac_ctrl2)
 | 
			
		||||
+		mvreg_write(pp, MVNETA_GMAC_CTRL_2, new_ctrl2);
 | 
			
		||||
+	if (new_clk != gmac_clk)
 | 
			
		||||
+		mvreg_write(pp, MVNETA_GMAC_CLOCK_DIVIDER, new_clk);
 | 
			
		||||
+	if (new_an != gmac_an)
 | 
			
		||||
+		mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, new_an);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static void mvneta_mac_link_down(struct net_device *ndev, unsigned int mode)
 | 
			
		||||
+{
 | 
			
		||||
+	struct mvneta_port *pp = netdev_priv(ndev);
 | 
			
		||||
+	u32 val;
 | 
			
		||||
+
 | 
			
		||||
+	mvneta_port_down(pp);
 | 
			
		||||
+
 | 
			
		||||
+	if (mode == MLO_AN_PHY || mode == MLO_AN_FIXED) {
 | 
			
		||||
+		val = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG);
 | 
			
		||||
+		val &= ~MVNETA_GMAC_FORCE_LINK_PASS;
 | 
			
		||||
+		val |= MVNETA_GMAC_FORCE_LINK_DOWN;
 | 
			
		||||
+		mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val);
 | 
			
		||||
 	}
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
-static int mvneta_mdio_probe(struct mvneta_port *pp)
 | 
			
		||||
+static void mvneta_mac_link_up(struct net_device *ndev, unsigned int mode,
 | 
			
		||||
+			       struct phy_device *phy)
 | 
			
		||||
 {
 | 
			
		||||
-	struct phy_device *phy_dev;
 | 
			
		||||
+	struct mvneta_port *pp = netdev_priv(ndev);
 | 
			
		||||
+	u32 val;
 | 
			
		||||
+
 | 
			
		||||
+	if (mode == MLO_AN_PHY || mode == MLO_AN_FIXED) {
 | 
			
		||||
+		val = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG);
 | 
			
		||||
+		val &= ~MVNETA_GMAC_FORCE_LINK_DOWN;
 | 
			
		||||
+		val |= MVNETA_GMAC_FORCE_LINK_PASS;
 | 
			
		||||
+		mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val);
 | 
			
		||||
+	}
 | 
			
		||||
 
 | 
			
		||||
-	phy_dev = of_phy_connect(pp->dev, pp->phy_node, mvneta_adjust_link, 0,
 | 
			
		||||
-				 pp->phy_interface);
 | 
			
		||||
-	if (!phy_dev) {
 | 
			
		||||
-		netdev_err(pp->dev, "could not find the PHY\n");
 | 
			
		||||
-		return -ENODEV;
 | 
			
		||||
-	}
 | 
			
		||||
-
 | 
			
		||||
-	phy_dev->supported &= PHY_GBIT_FEATURES;
 | 
			
		||||
-	phy_dev->advertising = phy_dev->supported;
 | 
			
		||||
-
 | 
			
		||||
-	pp->phy_dev = phy_dev;
 | 
			
		||||
-	pp->link    = 0;
 | 
			
		||||
-	pp->duplex  = 0;
 | 
			
		||||
-	pp->speed   = 0;
 | 
			
		||||
+	mvneta_port_up(pp);
 | 
			
		||||
+}
 | 
			
		||||
 
 | 
			
		||||
-	return 0;
 | 
			
		||||
+static const struct phylink_mac_ops mvneta_phylink_ops = {
 | 
			
		||||
+	.mac_get_support = mvneta_mac_support,
 | 
			
		||||
+	.mac_link_state = mvneta_mac_link_state,
 | 
			
		||||
+	.mac_an_restart = mvneta_mac_an_restart,
 | 
			
		||||
+	.mac_config = mvneta_mac_config,
 | 
			
		||||
+	.mac_link_down = mvneta_mac_link_down,
 | 
			
		||||
+	.mac_link_up = mvneta_mac_link_up,
 | 
			
		||||
+};
 | 
			
		||||
+
 | 
			
		||||
+static int mvneta_mdio_probe(struct mvneta_port *pp)
 | 
			
		||||
+{
 | 
			
		||||
+	int err = phylink_of_phy_connect(pp->phylink, pp->dn);
 | 
			
		||||
+	if (err)
 | 
			
		||||
+		netdev_err(pp->dev, "could not attach PHY\n");
 | 
			
		||||
+
 | 
			
		||||
+	return err;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
 static void mvneta_mdio_remove(struct mvneta_port *pp)
 | 
			
		||||
 {
 | 
			
		||||
-	phy_disconnect(pp->phy_dev);
 | 
			
		||||
-	pp->phy_dev = NULL;
 | 
			
		||||
+	phylink_disconnect_phy(pp->phylink);
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
 /* Electing a CPU must be done in an atomic way: it should be done
 | 
			
		||||
@@ -3501,10 +3568,7 @@ static int mvneta_ioctl(struct net_devic
 | 
			
		||||
 {
 | 
			
		||||
 	struct mvneta_port *pp = netdev_priv(dev);
 | 
			
		||||
 
 | 
			
		||||
-	if (!pp->phy_dev)
 | 
			
		||||
-		return -ENOTSUPP;
 | 
			
		||||
-
 | 
			
		||||
-	return phy_mii_ioctl(pp->phy_dev, ifr, cmd);
 | 
			
		||||
+	return phylink_mii_ioctl(pp->phylink, ifr, cmd);
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
 /* Ethtool methods */
 | 
			
		||||
@@ -3514,54 +3578,15 @@ int mvneta_ethtool_get_settings(struct n
 | 
			
		||||
 {
 | 
			
		||||
 	struct mvneta_port *pp = netdev_priv(dev);
 | 
			
		||||
 
 | 
			
		||||
-	if (!pp->phy_dev)
 | 
			
		||||
-		return -ENODEV;
 | 
			
		||||
-
 | 
			
		||||
-	return phy_ethtool_gset(pp->phy_dev, cmd);
 | 
			
		||||
+	return phylink_ethtool_get_settings(pp->phylink, cmd);
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
 /* Set settings (phy address, speed) for ethtools */
 | 
			
		||||
 int mvneta_ethtool_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 | 
			
		||||
 {
 | 
			
		||||
 	struct mvneta_port *pp = netdev_priv(dev);
 | 
			
		||||
-	struct phy_device *phydev = pp->phy_dev;
 | 
			
		||||
-
 | 
			
		||||
-	if (!phydev)
 | 
			
		||||
-		return -ENODEV;
 | 
			
		||||
 
 | 
			
		||||
-	if ((cmd->autoneg == AUTONEG_ENABLE) != pp->use_inband_status) {
 | 
			
		||||
-		u32 val;
 | 
			
		||||
-
 | 
			
		||||
-		mvneta_set_autoneg(pp, cmd->autoneg == AUTONEG_ENABLE);
 | 
			
		||||
-
 | 
			
		||||
-		if (cmd->autoneg == AUTONEG_DISABLE) {
 | 
			
		||||
-			val = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG);
 | 
			
		||||
-			val &= ~(MVNETA_GMAC_CONFIG_MII_SPEED |
 | 
			
		||||
-				 MVNETA_GMAC_CONFIG_GMII_SPEED |
 | 
			
		||||
-				 MVNETA_GMAC_CONFIG_FULL_DUPLEX);
 | 
			
		||||
-
 | 
			
		||||
-			if (phydev->duplex)
 | 
			
		||||
-				val |= MVNETA_GMAC_CONFIG_FULL_DUPLEX;
 | 
			
		||||
-
 | 
			
		||||
-			if (phydev->speed == SPEED_1000)
 | 
			
		||||
-				val |= MVNETA_GMAC_CONFIG_GMII_SPEED;
 | 
			
		||||
-			else if (phydev->speed == SPEED_100)
 | 
			
		||||
-				val |= MVNETA_GMAC_CONFIG_MII_SPEED;
 | 
			
		||||
-
 | 
			
		||||
-			mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val);
 | 
			
		||||
-		}
 | 
			
		||||
-
 | 
			
		||||
-		pp->use_inband_status = (cmd->autoneg == AUTONEG_ENABLE);
 | 
			
		||||
-		netdev_info(pp->dev, "autoneg status set to %i\n",
 | 
			
		||||
-			    pp->use_inband_status);
 | 
			
		||||
-
 | 
			
		||||
-		if (netif_running(dev)) {
 | 
			
		||||
-			mvneta_port_down(pp);
 | 
			
		||||
-			mvneta_port_up(pp);
 | 
			
		||||
-		}
 | 
			
		||||
-	}
 | 
			
		||||
-
 | 
			
		||||
-	return phy_ethtool_sset(pp->phy_dev, cmd);
 | 
			
		||||
+	return phylink_ethtool_set_settings(pp->phylink, cmd);
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
 /* Set interrupt coalescing for ethtools */
 | 
			
		||||
@@ -3669,7 +3694,8 @@ static void mvneta_ethtool_update_stats(
 | 
			
		||||
 {
 | 
			
		||||
 	const struct mvneta_statistic *s;
 | 
			
		||||
 	void __iomem *base = pp->base;
 | 
			
		||||
-	u32 high, low, val;
 | 
			
		||||
+	u32 high, low;
 | 
			
		||||
+	u64 val;
 | 
			
		||||
 	u64 val64;
 | 
			
		||||
 	int i;
 | 
			
		||||
 
 | 
			
		||||
@@ -3964,14 +3990,13 @@ static int mvneta_probe(struct platform_
 | 
			
		||||
 	const struct mbus_dram_target_info *dram_target_info;
 | 
			
		||||
 	struct resource *res;
 | 
			
		||||
 	struct device_node *dn = pdev->dev.of_node;
 | 
			
		||||
-	struct device_node *phy_node;
 | 
			
		||||
 	struct device_node *bm_node;
 | 
			
		||||
 	struct mvneta_port *pp;
 | 
			
		||||
 	struct net_device *dev;
 | 
			
		||||
+	struct phylink *phylink;
 | 
			
		||||
 	const char *dt_mac_addr;
 | 
			
		||||
 	char hw_mac_addr[ETH_ALEN];
 | 
			
		||||
 	const char *mac_from;
 | 
			
		||||
-	const char *managed;
 | 
			
		||||
 	int tx_csum_limit;
 | 
			
		||||
 	int phy_mode;
 | 
			
		||||
 	int err;
 | 
			
		||||
@@ -3987,31 +4012,11 @@ static int mvneta_probe(struct platform_
 | 
			
		||||
 		goto err_free_netdev;
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
-	phy_node = of_parse_phandle(dn, "phy", 0);
 | 
			
		||||
-	if (!phy_node) {
 | 
			
		||||
-		if (!of_phy_is_fixed_link(dn)) {
 | 
			
		||||
-			dev_err(&pdev->dev, "no PHY specified\n");
 | 
			
		||||
-			err = -ENODEV;
 | 
			
		||||
-			goto err_free_irq;
 | 
			
		||||
-		}
 | 
			
		||||
-
 | 
			
		||||
-		err = of_phy_register_fixed_link(dn);
 | 
			
		||||
-		if (err < 0) {
 | 
			
		||||
-			dev_err(&pdev->dev, "cannot register fixed PHY\n");
 | 
			
		||||
-			goto err_free_irq;
 | 
			
		||||
-		}
 | 
			
		||||
-
 | 
			
		||||
-		/* In the case of a fixed PHY, the DT node associated
 | 
			
		||||
-		 * to the PHY is the Ethernet MAC DT node.
 | 
			
		||||
-		 */
 | 
			
		||||
-		phy_node = of_node_get(dn);
 | 
			
		||||
-	}
 | 
			
		||||
-
 | 
			
		||||
 	phy_mode = of_get_phy_mode(dn);
 | 
			
		||||
 	if (phy_mode < 0) {
 | 
			
		||||
 		dev_err(&pdev->dev, "incorrect phy-mode\n");
 | 
			
		||||
 		err = -EINVAL;
 | 
			
		||||
-		goto err_put_phy_node;
 | 
			
		||||
+		goto err_free_irq;
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
 	dev->tx_queue_len = MVNETA_MAX_TXD;
 | 
			
		||||
@@ -4022,12 +4027,7 @@ static int mvneta_probe(struct platform_
 | 
			
		||||
 
 | 
			
		||||
 	pp = netdev_priv(dev);
 | 
			
		||||
 	spin_lock_init(&pp->lock);
 | 
			
		||||
-	pp->phy_node = phy_node;
 | 
			
		||||
-	pp->phy_interface = phy_mode;
 | 
			
		||||
-
 | 
			
		||||
-	err = of_property_read_string(dn, "managed", &managed);
 | 
			
		||||
-	pp->use_inband_status = (err == 0 &&
 | 
			
		||||
-				 strcmp(managed, "in-band-status") == 0);
 | 
			
		||||
+	pp->dn = dn;
 | 
			
		||||
 	pp->cpu_notifier.notifier_call = mvneta_percpu_notifier;
 | 
			
		||||
 
 | 
			
		||||
 	pp->rxq_def = rxq_def;
 | 
			
		||||
@@ -4037,7 +4037,7 @@ static int mvneta_probe(struct platform_
 | 
			
		||||
 	pp->clk = devm_clk_get(&pdev->dev, NULL);
 | 
			
		||||
 	if (IS_ERR(pp->clk)) {
 | 
			
		||||
 		err = PTR_ERR(pp->clk);
 | 
			
		||||
-		goto err_put_phy_node;
 | 
			
		||||
+		goto err_free_irq;
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
 	clk_prepare_enable(pp->clk);
 | 
			
		||||
@@ -4140,6 +4140,14 @@ static int mvneta_probe(struct platform_
 | 
			
		||||
 	dev->priv_flags |= IFF_UNICAST_FLT | IFF_LIVE_ADDR_CHANGE;
 | 
			
		||||
 	dev->gso_max_segs = MVNETA_MAX_TSO_SEGS;
 | 
			
		||||
 
 | 
			
		||||
+	phylink = phylink_create(dev, dn, phy_mode, &mvneta_phylink_ops);
 | 
			
		||||
+	if (IS_ERR(phylink)) {
 | 
			
		||||
+		err = PTR_ERR(phylink);
 | 
			
		||||
+		goto err_free_stats;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	pp->phylink = phylink;
 | 
			
		||||
+
 | 
			
		||||
 	err = register_netdev(dev);
 | 
			
		||||
 	if (err < 0) {
 | 
			
		||||
 		dev_err(&pdev->dev, "failed to register\n");
 | 
			
		||||
@@ -4151,13 +4159,6 @@ static int mvneta_probe(struct platform_
 | 
			
		||||
 
 | 
			
		||||
 	platform_set_drvdata(pdev, pp->dev);
 | 
			
		||||
 
 | 
			
		||||
-	if (pp->use_inband_status) {
 | 
			
		||||
-		struct phy_device *phy = of_phy_find_device(dn);
 | 
			
		||||
-
 | 
			
		||||
-		mvneta_fixed_link_update(pp, phy);
 | 
			
		||||
-
 | 
			
		||||
-		put_device(&phy->dev);
 | 
			
		||||
-	}
 | 
			
		||||
 
 | 
			
		||||
 	return 0;
 | 
			
		||||
 
 | 
			
		||||
@@ -4169,13 +4170,13 @@ err_netdev:
 | 
			
		||||
 				       1 << pp->id);
 | 
			
		||||
 	}
 | 
			
		||||
 err_free_stats:
 | 
			
		||||
+	if (pp->phylink)
 | 
			
		||||
+		phylink_destroy(pp->phylink);
 | 
			
		||||
 	free_percpu(pp->stats);
 | 
			
		||||
 err_free_ports:
 | 
			
		||||
 	free_percpu(pp->ports);
 | 
			
		||||
 err_clk:
 | 
			
		||||
 	clk_disable_unprepare(pp->clk);
 | 
			
		||||
-err_put_phy_node:
 | 
			
		||||
-	of_node_put(phy_node);
 | 
			
		||||
 err_free_irq:
 | 
			
		||||
 	irq_dispose_mapping(dev->irq);
 | 
			
		||||
 err_free_netdev:
 | 
			
		||||
@@ -4194,7 +4195,7 @@ static int mvneta_remove(struct platform
 | 
			
		||||
 	free_percpu(pp->ports);
 | 
			
		||||
 	free_percpu(pp->stats);
 | 
			
		||||
 	irq_dispose_mapping(dev->irq);
 | 
			
		||||
-	of_node_put(pp->phy_node);
 | 
			
		||||
+	phylink_destroy(pp->phylink);
 | 
			
		||||
 	free_netdev(dev);
 | 
			
		||||
 
 | 
			
		||||
 	if (pp->bm_priv) {
 | 
			
		||||
@@ -0,0 +1,80 @@
 | 
			
		||||
From 9be436bdb67c1f4aa9f33f2477f94e1f58a0ff02 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
Date: Fri, 2 Oct 2015 22:46:54 +0100
 | 
			
		||||
Subject: [PATCH 723/744] phy: fixed-phy: remove fixed_phy_update_state()
 | 
			
		||||
 | 
			
		||||
mvneta is the only user of fixed_phy_update_state(), which has been
 | 
			
		||||
converted to use phylink instead.  Remove fixed_phy_update_state().
 | 
			
		||||
 | 
			
		||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
 | 
			
		||||
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
---
 | 
			
		||||
 drivers/net/phy/fixed_phy.c | 31 -------------------------------
 | 
			
		||||
 include/linux/phy_fixed.h   |  9 ---------
 | 
			
		||||
 2 files changed, 40 deletions(-)
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/phy/fixed_phy.c
 | 
			
		||||
+++ b/drivers/net/phy/fixed_phy.c
 | 
			
		||||
@@ -115,37 +115,6 @@ int fixed_phy_set_link_update(struct phy
 | 
			
		||||
 }
 | 
			
		||||
 EXPORT_SYMBOL_GPL(fixed_phy_set_link_update);
 | 
			
		||||
 
 | 
			
		||||
-int fixed_phy_update_state(struct phy_device *phydev,
 | 
			
		||||
-			   const struct fixed_phy_status *status,
 | 
			
		||||
-			   const struct fixed_phy_status *changed)
 | 
			
		||||
-{
 | 
			
		||||
-	struct fixed_mdio_bus *fmb = &platform_fmb;
 | 
			
		||||
-	struct fixed_phy *fp;
 | 
			
		||||
-
 | 
			
		||||
-	if (!phydev || phydev->bus != fmb->mii_bus)
 | 
			
		||||
-		return -EINVAL;
 | 
			
		||||
-
 | 
			
		||||
-	list_for_each_entry(fp, &fmb->phys, node) {
 | 
			
		||||
-		if (fp->addr == phydev->addr) {
 | 
			
		||||
-			write_seqcount_begin(&fp->seqcount);
 | 
			
		||||
-#define _UPD(x) if (changed->x) \
 | 
			
		||||
-	fp->status.x = status->x
 | 
			
		||||
-			_UPD(link);
 | 
			
		||||
-			_UPD(speed);
 | 
			
		||||
-			_UPD(duplex);
 | 
			
		||||
-			_UPD(pause);
 | 
			
		||||
-			_UPD(asym_pause);
 | 
			
		||||
-#undef _UPD
 | 
			
		||||
-			fixed_phy_update(fp);
 | 
			
		||||
-			write_seqcount_end(&fp->seqcount);
 | 
			
		||||
-			return 0;
 | 
			
		||||
-		}
 | 
			
		||||
-	}
 | 
			
		||||
-
 | 
			
		||||
-	return -ENOENT;
 | 
			
		||||
-}
 | 
			
		||||
-EXPORT_SYMBOL(fixed_phy_update_state);
 | 
			
		||||
-
 | 
			
		||||
 int fixed_phy_add(unsigned int irq, int phy_addr,
 | 
			
		||||
 		  struct fixed_phy_status *status,
 | 
			
		||||
 		  int link_gpio)
 | 
			
		||||
--- a/include/linux/phy_fixed.h
 | 
			
		||||
+++ b/include/linux/phy_fixed.h
 | 
			
		||||
@@ -23,9 +23,6 @@ extern void fixed_phy_del(int phy_addr);
 | 
			
		||||
 extern int fixed_phy_set_link_update(struct phy_device *phydev,
 | 
			
		||||
 			int (*link_update)(struct net_device *,
 | 
			
		||||
 					   struct fixed_phy_status *));
 | 
			
		||||
-extern int fixed_phy_update_state(struct phy_device *phydev,
 | 
			
		||||
-			   const struct fixed_phy_status *status,
 | 
			
		||||
-			   const struct fixed_phy_status *changed);
 | 
			
		||||
 #else
 | 
			
		||||
 static inline int fixed_phy_add(unsigned int irq, int phy_id,
 | 
			
		||||
 				struct fixed_phy_status *status,
 | 
			
		||||
@@ -50,12 +47,6 @@ static inline int fixed_phy_set_link_upd
 | 
			
		||||
 {
 | 
			
		||||
 	return -ENODEV;
 | 
			
		||||
 }
 | 
			
		||||
-static inline int fixed_phy_update_state(struct phy_device *phydev,
 | 
			
		||||
-			   const struct fixed_phy_status *status,
 | 
			
		||||
-			   const struct fixed_phy_status *changed)
 | 
			
		||||
-{
 | 
			
		||||
-	return -ENODEV;
 | 
			
		||||
-}
 | 
			
		||||
 #endif /* CONFIG_FIXED_PHY */
 | 
			
		||||
 
 | 
			
		||||
 #endif /* __PHY_FIXED_H */
 | 
			
		||||
@@ -0,0 +1,48 @@
 | 
			
		||||
From d6bd25b692378ec17bdb1023d398c03c45829947 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
Date: Thu, 1 Oct 2015 20:27:19 +0100
 | 
			
		||||
Subject: [PATCH 724/744] phylink: add ethtool nway_reset support
 | 
			
		||||
 | 
			
		||||
Add ethtool nway_reset support to phylink, to allow userspace to
 | 
			
		||||
request a re-negotiation of the link.
 | 
			
		||||
 | 
			
		||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
 | 
			
		||||
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
---
 | 
			
		||||
 drivers/net/phy/phylink.c | 14 ++++++++++++++
 | 
			
		||||
 include/linux/phylink.h   |  1 +
 | 
			
		||||
 2 files changed, 15 insertions(+)
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/phy/phylink.c
 | 
			
		||||
+++ b/drivers/net/phy/phylink.c
 | 
			
		||||
@@ -687,6 +687,20 @@ int phylink_ethtool_set_settings(struct
 | 
			
		||||
 }
 | 
			
		||||
 EXPORT_SYMBOL_GPL(phylink_ethtool_set_settings);
 | 
			
		||||
 
 | 
			
		||||
+int phylink_ethtool_nway_reset(struct phylink *pl)
 | 
			
		||||
+{
 | 
			
		||||
+	int ret = 0;
 | 
			
		||||
+
 | 
			
		||||
+	mutex_lock(&pl->config_mutex);
 | 
			
		||||
+	if (pl->phydev)
 | 
			
		||||
+		ret = genphy_restart_aneg(pl->phydev);
 | 
			
		||||
+	phylink_mac_an_restart(pl);
 | 
			
		||||
+	mutex_unlock(&pl->config_mutex);
 | 
			
		||||
+
 | 
			
		||||
+	return ret;
 | 
			
		||||
+}
 | 
			
		||||
+EXPORT_SYMBOL_GPL(phylink_ethtool_nway_reset);
 | 
			
		||||
+
 | 
			
		||||
 /* This emulates MII registers for a fixed-mode phy operating as per the
 | 
			
		||||
  * passed in state. "aneg" defines if we report negotiation is possible.
 | 
			
		||||
  *
 | 
			
		||||
--- a/include/linux/phylink.h
 | 
			
		||||
+++ b/include/linux/phylink.h
 | 
			
		||||
@@ -65,6 +65,7 @@ void phylink_stop(struct phylink *);
 | 
			
		||||
 
 | 
			
		||||
 int phylink_ethtool_get_settings(struct phylink *, struct ethtool_cmd *);
 | 
			
		||||
 int phylink_ethtool_set_settings(struct phylink *, struct ethtool_cmd *);
 | 
			
		||||
+int phylink_ethtool_nway_reset(struct phylink *);
 | 
			
		||||
 int phylink_mii_ioctl(struct phylink *, struct ifreq *, int);
 | 
			
		||||
 
 | 
			
		||||
 void phylink_set_link_port(struct phylink *pl, u32 support, u8 port);
 | 
			
		||||
@@ -0,0 +1,38 @@
 | 
			
		||||
From 244bee2889d08f876c64c335765a8ea6de0f5381 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
Date: Thu, 1 Oct 2015 19:40:31 +0100
 | 
			
		||||
Subject: [PATCH 725/744] net: mvneta: add nway_reset support
 | 
			
		||||
 | 
			
		||||
Add ethtool nway_reset support to mvneta via phylink, so that userspace
 | 
			
		||||
can request the link in whatever mode to be renegotiated via
 | 
			
		||||
ethtool -r ethX.
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
---
 | 
			
		||||
 drivers/net/ethernet/marvell/mvneta.c | 8 ++++++++
 | 
			
		||||
 1 file changed, 8 insertions(+)
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
+++ b/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
@@ -3589,6 +3589,13 @@ int mvneta_ethtool_set_settings(struct n
 | 
			
		||||
 	return phylink_ethtool_set_settings(pp->phylink, cmd);
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
+static int mvneta_ethtool_nway_reset(struct net_device *dev)
 | 
			
		||||
+{
 | 
			
		||||
+	struct mvneta_port *pp = netdev_priv(dev);
 | 
			
		||||
+
 | 
			
		||||
+	return phylink_ethtool_nway_reset(pp->phylink);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
 /* Set interrupt coalescing for ethtools */
 | 
			
		||||
 static int mvneta_ethtool_set_coalesce(struct net_device *dev,
 | 
			
		||||
 				       struct ethtool_coalesce *c)
 | 
			
		||||
@@ -3853,6 +3860,7 @@ const struct ethtool_ops mvneta_eth_tool
 | 
			
		||||
 	.get_link       = ethtool_op_get_link,
 | 
			
		||||
 	.get_settings   = mvneta_ethtool_get_settings,
 | 
			
		||||
 	.set_settings   = mvneta_ethtool_set_settings,
 | 
			
		||||
+	.nway_reset	= mvneta_ethtool_nway_reset,
 | 
			
		||||
 	.set_coalesce   = mvneta_ethtool_set_coalesce,
 | 
			
		||||
 	.get_coalesce   = mvneta_ethtool_get_coalesce,
 | 
			
		||||
 	.get_drvinfo    = mvneta_ethtool_get_drvinfo,
 | 
			
		||||
@@ -0,0 +1,262 @@
 | 
			
		||||
From f566177aa6661e646b83526f24391a568ffd1a75 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
Date: Thu, 1 Oct 2015 20:32:07 +0100
 | 
			
		||||
Subject: [PATCH 726/744] phylink: add flow control support
 | 
			
		||||
 | 
			
		||||
Add flow control support, including ethtool support, to phylink.  We
 | 
			
		||||
add support to allow ethtool to get and set the current flow control
 | 
			
		||||
settings, and the 802.3 specified resolution for the local and remote
 | 
			
		||||
link partner abilities.
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
---
 | 
			
		||||
 drivers/net/phy/phylink.c | 145 +++++++++++++++++++++++++++++++++++++++++-----
 | 
			
		||||
 include/linux/phylink.h   |   8 +++
 | 
			
		||||
 2 files changed, 139 insertions(+), 14 deletions(-)
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/phy/phylink.c
 | 
			
		||||
+++ b/drivers/net/phy/phylink.c
 | 
			
		||||
@@ -91,10 +91,12 @@ static int phylink_parse_fixedlink(struc
 | 
			
		||||
 		pl->link_config.an_complete = 1;
 | 
			
		||||
 		pl->link_config.speed = speed;
 | 
			
		||||
 		pl->link_config.duplex = DUPLEX_HALF;
 | 
			
		||||
-		pl->link_config.pause = MLO_PAUSE_NONE;
 | 
			
		||||
 
 | 
			
		||||
 		if (of_property_read_bool(fixed_node, "full-duplex"))
 | 
			
		||||
 			pl->link_config.duplex = DUPLEX_FULL;
 | 
			
		||||
+
 | 
			
		||||
+		/* We treat the "pause" and "asym-pause" terminology as
 | 
			
		||||
+		 * defining the link partner's ability. */
 | 
			
		||||
 		if (of_property_read_bool(fixed_node, "pause"))
 | 
			
		||||
 			pl->link_config.pause |= MLO_PAUSE_SYM;
 | 
			
		||||
 		if (of_property_read_bool(fixed_node, "asym-pause"))
 | 
			
		||||
@@ -118,7 +120,6 @@ static int phylink_parse_fixedlink(struc
 | 
			
		||||
 			pl->link_config.duplex = be32_to_cpu(fixed_prop[1]) ?
 | 
			
		||||
 						DUPLEX_FULL : DUPLEX_HALF;
 | 
			
		||||
 			pl->link_config.speed = be32_to_cpu(fixed_prop[2]);
 | 
			
		||||
-			pl->link_config.pause = MLO_PAUSE_NONE;
 | 
			
		||||
 			if (be32_to_cpu(fixed_prop[3]))
 | 
			
		||||
 				pl->link_config.pause |= MLO_PAUSE_SYM;
 | 
			
		||||
 			if (be32_to_cpu(fixed_prop[4]))
 | 
			
		||||
@@ -130,16 +131,6 @@ static int phylink_parse_fixedlink(struc
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
 	if (pl->link_an_mode == MLO_AN_FIXED) {
 | 
			
		||||
-		/* Generate the supported/advertising masks */
 | 
			
		||||
-		if (pl->link_config.pause & MLO_PAUSE_SYM) {
 | 
			
		||||
-			pl->link_config.supported |= SUPPORTED_Pause;
 | 
			
		||||
-			pl->link_config.advertising |= ADVERTISED_Pause;
 | 
			
		||||
-		}
 | 
			
		||||
-		if (pl->link_config.pause & MLO_PAUSE_ASYM) {
 | 
			
		||||
-			pl->link_config.supported |= SUPPORTED_Asym_Pause;
 | 
			
		||||
-			pl->link_config.advertising |= ADVERTISED_Asym_Pause;
 | 
			
		||||
-		}
 | 
			
		||||
-
 | 
			
		||||
 		if (pl->link_config.speed > SPEED_1000 &&
 | 
			
		||||
 		    pl->link_config.duplex != DUPLEX_FULL)
 | 
			
		||||
 			netdev_warn(pl->netdev, "fixed link specifies half duplex for %dMbps link?\n",
 | 
			
		||||
@@ -242,6 +233,56 @@ static void phylink_get_fixed_state(stru
 | 
			
		||||
 		state->link = !!gpiod_get_value(pl->link_gpio);
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
+/* Flow control is resolved according to our and the link partners
 | 
			
		||||
+ * advertisments using the following drawn from the 802.3 specs:
 | 
			
		||||
+ *  Local device  Link partner
 | 
			
		||||
+ *  Pause AsymDir Pause AsymDir Result
 | 
			
		||||
+ *    1     X       1     X     TX+RX
 | 
			
		||||
+ *    0     1       1     1     RX
 | 
			
		||||
+ *    1     1       0     1     TX
 | 
			
		||||
+ */
 | 
			
		||||
+static void phylink_resolve_flow(struct phylink *pl,
 | 
			
		||||
+	struct phylink_link_state *state)
 | 
			
		||||
+{
 | 
			
		||||
+	int new_pause = 0;
 | 
			
		||||
+
 | 
			
		||||
+	if (pl->link_config.pause & MLO_PAUSE_AN) {
 | 
			
		||||
+		int pause = 0;
 | 
			
		||||
+
 | 
			
		||||
+		if (pl->link_config.advertising & ADVERTISED_Pause)
 | 
			
		||||
+			pause |= MLO_PAUSE_SYM;
 | 
			
		||||
+		if (pl->link_config.advertising & ADVERTISED_Asym_Pause)
 | 
			
		||||
+			pause |= MLO_PAUSE_ASYM;
 | 
			
		||||
+
 | 
			
		||||
+		pause &= state->pause;
 | 
			
		||||
+
 | 
			
		||||
+		if (pause & MLO_PAUSE_SYM)
 | 
			
		||||
+			new_pause = MLO_PAUSE_TX | MLO_PAUSE_RX;
 | 
			
		||||
+		else if (pause & MLO_PAUSE_ASYM)
 | 
			
		||||
+			new_pause = state->pause & MLO_PAUSE_SYM ?
 | 
			
		||||
+				 MLO_PAUSE_RX : MLO_PAUSE_TX;
 | 
			
		||||
+	} else {
 | 
			
		||||
+		new_pause = pl->link_config.pause & MLO_PAUSE_TXRX_MASK;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	state->pause &= ~MLO_PAUSE_TXRX_MASK;
 | 
			
		||||
+	state->pause |= new_pause;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static const char *phylink_pause_to_str(int pause)
 | 
			
		||||
+{
 | 
			
		||||
+	switch (pause & MLO_PAUSE_TXRX_MASK) {
 | 
			
		||||
+	case MLO_PAUSE_TX | MLO_PAUSE_RX:
 | 
			
		||||
+		return "rx/tx";
 | 
			
		||||
+	case MLO_PAUSE_TX:
 | 
			
		||||
+		return "tx";
 | 
			
		||||
+	case MLO_PAUSE_RX:
 | 
			
		||||
+		return "rx";
 | 
			
		||||
+	default:
 | 
			
		||||
+		return "off";
 | 
			
		||||
+	}
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
 extern const char *phy_speed_to_str(int speed);
 | 
			
		||||
 
 | 
			
		||||
 static void phylink_resolve(struct work_struct *w)
 | 
			
		||||
@@ -257,6 +298,7 @@ static void phylink_resolve(struct work_
 | 
			
		||||
 		switch (pl->link_an_mode) {
 | 
			
		||||
 		case MLO_AN_PHY:
 | 
			
		||||
 			link_state = pl->phy_state;
 | 
			
		||||
+			phylink_resolve_flow(pl, &link_state);
 | 
			
		||||
 			break;
 | 
			
		||||
 
 | 
			
		||||
 		case MLO_AN_FIXED:
 | 
			
		||||
@@ -265,9 +307,12 @@ static void phylink_resolve(struct work_
 | 
			
		||||
 
 | 
			
		||||
 		case MLO_AN_SGMII:
 | 
			
		||||
 			phylink_get_mac_state(pl, &link_state);
 | 
			
		||||
-			if (pl->phydev)
 | 
			
		||||
+			if (pl->phydev) {
 | 
			
		||||
 				link_state.link = link_state.link &&
 | 
			
		||||
 						  pl->phy_state.link;
 | 
			
		||||
+				link_state.pause |= pl->phy_state.pause;
 | 
			
		||||
+				phylink_resolve_flow(pl, &link_state);
 | 
			
		||||
+			}
 | 
			
		||||
 			break;
 | 
			
		||||
 
 | 
			
		||||
 		case MLO_AN_8023Z:
 | 
			
		||||
@@ -297,7 +342,7 @@ static void phylink_resolve(struct work_
 | 
			
		||||
 				    "Link is Up - %s/%s - flow control %s\n",
 | 
			
		||||
 				    phy_speed_to_str(link_state.speed),
 | 
			
		||||
 				    link_state.duplex ? "Full" : "Half",
 | 
			
		||||
-				    link_state.pause ? "rx/tx" : "off");
 | 
			
		||||
+				    phylink_pause_to_str(link_state.pause));
 | 
			
		||||
 		}
 | 
			
		||||
 	}
 | 
			
		||||
 	mutex_unlock(&pl->state_mutex);
 | 
			
		||||
@@ -326,6 +371,7 @@ struct phylink *phylink_create(struct ne
 | 
			
		||||
 	pl->link_interface = iface;
 | 
			
		||||
 	pl->link_port_support = SUPPORTED_MII;
 | 
			
		||||
 	pl->link_port = PORT_MII;
 | 
			
		||||
+	pl->link_config.pause = MLO_PAUSE_AN;
 | 
			
		||||
 	pl->ops = ops;
 | 
			
		||||
 	__set_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state);
 | 
			
		||||
 
 | 
			
		||||
@@ -507,6 +553,7 @@ void phylink_start(struct phylink *pl)
 | 
			
		||||
 	 * a fixed-link to start with the correct parameters, and also
 | 
			
		||||
 	 * ensures that we set the appropriate advertisment for Serdes links.
 | 
			
		||||
 	 */
 | 
			
		||||
+	phylink_resolve_flow(pl, &pl->link_config);
 | 
			
		||||
 	phylink_mac_config(pl, &pl->link_config);
 | 
			
		||||
 
 | 
			
		||||
 	clear_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state);
 | 
			
		||||
@@ -701,6 +748,76 @@ int phylink_ethtool_nway_reset(struct ph
 | 
			
		||||
 }
 | 
			
		||||
 EXPORT_SYMBOL_GPL(phylink_ethtool_nway_reset);
 | 
			
		||||
 
 | 
			
		||||
+void phylink_ethtool_get_pauseparam(struct phylink *pl,
 | 
			
		||||
+				    struct ethtool_pauseparam *pause)
 | 
			
		||||
+{
 | 
			
		||||
+	mutex_lock(&pl->config_mutex);
 | 
			
		||||
+
 | 
			
		||||
+	pause->autoneg = !!(pl->link_config.pause & MLO_PAUSE_AN);
 | 
			
		||||
+	pause->rx_pause = !!(pl->link_config.pause & MLO_PAUSE_RX);
 | 
			
		||||
+	pause->tx_pause = !!(pl->link_config.pause & MLO_PAUSE_TX);
 | 
			
		||||
+
 | 
			
		||||
+	mutex_unlock(&pl->config_mutex);
 | 
			
		||||
+}
 | 
			
		||||
+EXPORT_SYMBOL_GPL(phylink_ethtool_get_pauseparam);
 | 
			
		||||
+
 | 
			
		||||
+static int __phylink_ethtool_set_pauseparam(struct phylink *pl,
 | 
			
		||||
+					    struct ethtool_pauseparam *pause)
 | 
			
		||||
+{
 | 
			
		||||
+	struct phylink_link_state *config = &pl->link_config;
 | 
			
		||||
+
 | 
			
		||||
+	if (!(config->supported & (SUPPORTED_Pause | SUPPORTED_Asym_Pause)))
 | 
			
		||||
+		return -EOPNOTSUPP;
 | 
			
		||||
+
 | 
			
		||||
+	if (!(config->supported & SUPPORTED_Asym_Pause) &&
 | 
			
		||||
+	    !pause->autoneg && pause->rx_pause != pause->tx_pause)
 | 
			
		||||
+		return -EINVAL;
 | 
			
		||||
+
 | 
			
		||||
+	config->pause &= ~(MLO_PAUSE_AN | MLO_PAUSE_TXRX_MASK);
 | 
			
		||||
+
 | 
			
		||||
+	if (pause->autoneg)
 | 
			
		||||
+		config->pause |= MLO_PAUSE_AN;
 | 
			
		||||
+	if (pause->rx_pause)
 | 
			
		||||
+		config->pause |= MLO_PAUSE_RX;
 | 
			
		||||
+	if (pause->tx_pause)
 | 
			
		||||
+		config->pause |= MLO_PAUSE_TX;
 | 
			
		||||
+
 | 
			
		||||
+	switch (pl->link_an_mode) {
 | 
			
		||||
+	case MLO_AN_PHY:
 | 
			
		||||
+		/* Silently mark the carrier down, and then trigger a resolve */
 | 
			
		||||
+		netif_carrier_off(pl->netdev);
 | 
			
		||||
+		phylink_run_resolve(pl);
 | 
			
		||||
+		break;
 | 
			
		||||
+
 | 
			
		||||
+	case MLO_AN_FIXED:
 | 
			
		||||
+		/* Should we allow fixed links to change against the config? */
 | 
			
		||||
+		phylink_resolve_flow(pl, config);
 | 
			
		||||
+		phylink_mac_config(pl, config);
 | 
			
		||||
+		break;
 | 
			
		||||
+
 | 
			
		||||
+	case MLO_AN_SGMII:
 | 
			
		||||
+	case MLO_AN_8023Z:
 | 
			
		||||
+		phylink_mac_config(pl, config);
 | 
			
		||||
+		phylink_mac_an_restart(pl);
 | 
			
		||||
+		break;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	return 0;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+int phylink_ethtool_set_pauseparam(struct phylink *pl,
 | 
			
		||||
+				   struct ethtool_pauseparam *pause)
 | 
			
		||||
+{
 | 
			
		||||
+	int ret;
 | 
			
		||||
+
 | 
			
		||||
+	mutex_lock(&pl->config_mutex);
 | 
			
		||||
+	ret = __phylink_ethtool_set_pauseparam(pl, pause);
 | 
			
		||||
+	mutex_unlock(&pl->config_mutex);
 | 
			
		||||
+
 | 
			
		||||
+	return ret;
 | 
			
		||||
+}
 | 
			
		||||
+EXPORT_SYMBOL_GPL(phylink_ethtool_set_pauseparam);
 | 
			
		||||
+
 | 
			
		||||
 /* This emulates MII registers for a fixed-mode phy operating as per the
 | 
			
		||||
  * passed in state. "aneg" defines if we report negotiation is possible.
 | 
			
		||||
  *
 | 
			
		||||
--- a/include/linux/phylink.h
 | 
			
		||||
+++ b/include/linux/phylink.h
 | 
			
		||||
@@ -13,6 +13,10 @@ enum {
 | 
			
		||||
 	MLO_PAUSE_NONE,
 | 
			
		||||
 	MLO_PAUSE_ASYM = BIT(0),
 | 
			
		||||
 	MLO_PAUSE_SYM = BIT(1),
 | 
			
		||||
+	MLO_PAUSE_RX = BIT(2),
 | 
			
		||||
+	MLO_PAUSE_TX = BIT(3),
 | 
			
		||||
+	MLO_PAUSE_TXRX_MASK = MLO_PAUSE_TX | MLO_PAUSE_RX,
 | 
			
		||||
+	MLO_PAUSE_AN = BIT(4),
 | 
			
		||||
 
 | 
			
		||||
 	MLO_AN_PHY = 0,
 | 
			
		||||
 	MLO_AN_FIXED,
 | 
			
		||||
@@ -66,6 +70,10 @@ void phylink_stop(struct phylink *);
 | 
			
		||||
 int phylink_ethtool_get_settings(struct phylink *, struct ethtool_cmd *);
 | 
			
		||||
 int phylink_ethtool_set_settings(struct phylink *, struct ethtool_cmd *);
 | 
			
		||||
 int phylink_ethtool_nway_reset(struct phylink *);
 | 
			
		||||
+void phylink_ethtool_get_pauseparam(struct phylink *,
 | 
			
		||||
+				    struct ethtool_pauseparam *);
 | 
			
		||||
+int phylink_ethtool_set_pauseparam(struct phylink *,
 | 
			
		||||
+				   struct ethtool_pauseparam *);
 | 
			
		||||
 int phylink_mii_ioctl(struct phylink *, struct ifreq *, int);
 | 
			
		||||
 
 | 
			
		||||
 void phylink_set_link_port(struct phylink *pl, u32 support, u8 port);
 | 
			
		||||
@@ -0,0 +1,66 @@
 | 
			
		||||
From 7bd34822b9922beb22a6384d9190646105d259d8 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
Date: Thu, 1 Oct 2015 17:41:44 +0100
 | 
			
		||||
Subject: [PATCH 727/744] net: mvneta: add flow control support via phylink
 | 
			
		||||
 | 
			
		||||
Add flow control support to mvneta, including the ethtool hooks.  This
 | 
			
		||||
uses the phylink code to calculate the result of autonegotiation where
 | 
			
		||||
a phy is attached, and to handle the ethtool settings.
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
---
 | 
			
		||||
 drivers/net/ethernet/marvell/mvneta.c | 22 +++++++++++++++++++++-
 | 
			
		||||
 1 file changed, 21 insertions(+), 1 deletion(-)
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
+++ b/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
@@ -3208,6 +3208,8 @@ static void mvneta_mac_config(struct net
 | 
			
		||||
 
 | 
			
		||||
 	if (state->advertising & ADVERTISED_Pause)
 | 
			
		||||
 		new_an |= MVNETA_GMAC_ADVERT_SYM_FLOW_CTRL;
 | 
			
		||||
+	if (state->pause & MLO_PAUSE_TXRX_MASK)
 | 
			
		||||
+		new_an |= MVNETA_GMAC_CONFIG_FLOW_CTRL;
 | 
			
		||||
 
 | 
			
		||||
 	switch (mode) {
 | 
			
		||||
 	case MLO_AN_SGMII:
 | 
			
		||||
@@ -3232,7 +3234,7 @@ static void mvneta_mac_config(struct net
 | 
			
		||||
 			 /* The MAC only supports FD mode */
 | 
			
		||||
 			 MVNETA_GMAC_CONFIG_FULL_DUPLEX;
 | 
			
		||||
 
 | 
			
		||||
-		if (state->an_enabled)
 | 
			
		||||
+		if (state->pause & MLO_PAUSE_AN && state->an_enabled)
 | 
			
		||||
 			new_an |= MVNETA_GMAC_AN_FLOW_CTRL_EN;
 | 
			
		||||
 		break;
 | 
			
		||||
 
 | 
			
		||||
@@ -3685,6 +3687,22 @@ static int mvneta_ethtool_set_ringparam(
 | 
			
		||||
 	return 0;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
+static void mvneta_ethtool_get_pauseparam(struct net_device *dev,
 | 
			
		||||
+					  struct ethtool_pauseparam *pause)
 | 
			
		||||
+{
 | 
			
		||||
+	struct mvneta_port *pp = netdev_priv(dev);
 | 
			
		||||
+
 | 
			
		||||
+	phylink_ethtool_get_pauseparam(pp->phylink, pause);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static int mvneta_ethtool_set_pauseparam(struct net_device *dev,
 | 
			
		||||
+					 struct ethtool_pauseparam *pause)
 | 
			
		||||
+{
 | 
			
		||||
+	struct mvneta_port *pp = netdev_priv(dev);
 | 
			
		||||
+
 | 
			
		||||
+	return phylink_ethtool_set_pauseparam(pp->phylink, pause);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
 static void mvneta_ethtool_get_strings(struct net_device *netdev, u32 sset,
 | 
			
		||||
 				       u8 *data)
 | 
			
		||||
 {
 | 
			
		||||
@@ -3866,6 +3884,8 @@ const struct ethtool_ops mvneta_eth_tool
 | 
			
		||||
 	.get_drvinfo    = mvneta_ethtool_get_drvinfo,
 | 
			
		||||
 	.get_ringparam  = mvneta_ethtool_get_ringparam,
 | 
			
		||||
 	.set_ringparam	= mvneta_ethtool_set_ringparam,
 | 
			
		||||
+	.get_pauseparam	= mvneta_ethtool_get_pauseparam,
 | 
			
		||||
+	.set_pauseparam	= mvneta_ethtool_set_pauseparam,
 | 
			
		||||
 	.get_strings	= mvneta_ethtool_get_strings,
 | 
			
		||||
 	.get_ethtool_stats = mvneta_ethtool_get_stats,
 | 
			
		||||
 	.get_sset_count	= mvneta_ethtool_get_sset_count,
 | 
			
		||||
@@ -0,0 +1,32 @@
 | 
			
		||||
From 62f8a12044265df11531750a240e516a5f1ff433 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
Date: Thu, 1 Oct 2015 00:34:08 +0100
 | 
			
		||||
Subject: [PATCH 728/744] net: mvneta: enable flow control for PHY connections
 | 
			
		||||
 | 
			
		||||
Enable flow control support for PHY connections by indicating our
 | 
			
		||||
support via the ethtool capabilities.  phylink takes care of the
 | 
			
		||||
appropriate handling.
 | 
			
		||||
 | 
			
		||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
 | 
			
		||||
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
---
 | 
			
		||||
 drivers/net/ethernet/marvell/mvneta.c | 2 ++
 | 
			
		||||
 1 file changed, 2 insertions(+)
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
+++ b/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
@@ -3127,12 +3127,14 @@ static int mvneta_mac_support(struct net
 | 
			
		||||
 		state->supported = PHY_10BT_FEATURES |
 | 
			
		||||
 				   PHY_100BT_FEATURES |
 | 
			
		||||
 				   SUPPORTED_1000baseT_Full |
 | 
			
		||||
+				   SUPPORTED_Pause |
 | 
			
		||||
 				   SUPPORTED_Autoneg;
 | 
			
		||||
 		state->advertising = ADVERTISED_10baseT_Half |
 | 
			
		||||
 				     ADVERTISED_10baseT_Full |
 | 
			
		||||
 				     ADVERTISED_100baseT_Half |
 | 
			
		||||
 				     ADVERTISED_100baseT_Full |
 | 
			
		||||
 				     ADVERTISED_1000baseT_Full |
 | 
			
		||||
+				     ADVERTISED_Pause |
 | 
			
		||||
 				     ADVERTISED_Autoneg;
 | 
			
		||||
 		state->an_enabled = 1;
 | 
			
		||||
 		break;
 | 
			
		||||
@@ -0,0 +1,53 @@
 | 
			
		||||
From 4c3e2dc08a11fb1273ca62467f1d06e59866bad3 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Russell King <rmk+kernel@armlinux.org.uk>
 | 
			
		||||
Date: Tue, 12 Jul 2016 00:04:13 +0100
 | 
			
		||||
Subject: [PATCH 729/744] net: mvneta: enable flow control for fixed
 | 
			
		||||
 connections
 | 
			
		||||
 | 
			
		||||
Allow symetric flow control to be enabled for fixed link connections as
 | 
			
		||||
well as other types of connections by setting the supported and
 | 
			
		||||
advertised capability bits.
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
 | 
			
		||||
---
 | 
			
		||||
 drivers/net/ethernet/marvell/mvneta.c | 11 +++++++----
 | 
			
		||||
 1 file changed, 7 insertions(+), 4 deletions(-)
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
+++ b/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
@@ -3114,9 +3114,9 @@ static int mvneta_mac_support(struct net
 | 
			
		||||
 	switch (mode) {
 | 
			
		||||
 	case MLO_AN_8023Z:
 | 
			
		||||
 		state->supported = SUPPORTED_1000baseT_Full |
 | 
			
		||||
-				   SUPPORTED_Autoneg | SUPPORTED_Pause;
 | 
			
		||||
+				   SUPPORTED_Autoneg;
 | 
			
		||||
 		state->advertising = ADVERTISED_1000baseT_Full |
 | 
			
		||||
-				     ADVERTISED_Autoneg | ADVERTISED_Pause;
 | 
			
		||||
+				     ADVERTISED_Autoneg;
 | 
			
		||||
 		state->an_enabled = 1;
 | 
			
		||||
 		break;
 | 
			
		||||
 
 | 
			
		||||
@@ -3127,18 +3127,21 @@ static int mvneta_mac_support(struct net
 | 
			
		||||
 		state->supported = PHY_10BT_FEATURES |
 | 
			
		||||
 				   PHY_100BT_FEATURES |
 | 
			
		||||
 				   SUPPORTED_1000baseT_Full |
 | 
			
		||||
-				   SUPPORTED_Pause |
 | 
			
		||||
 				   SUPPORTED_Autoneg;
 | 
			
		||||
 		state->advertising = ADVERTISED_10baseT_Half |
 | 
			
		||||
 				     ADVERTISED_10baseT_Full |
 | 
			
		||||
 				     ADVERTISED_100baseT_Half |
 | 
			
		||||
 				     ADVERTISED_100baseT_Full |
 | 
			
		||||
 				     ADVERTISED_1000baseT_Full |
 | 
			
		||||
-				     ADVERTISED_Pause |
 | 
			
		||||
 				     ADVERTISED_Autoneg;
 | 
			
		||||
 		state->an_enabled = 1;
 | 
			
		||||
 		break;
 | 
			
		||||
 	}
 | 
			
		||||
+
 | 
			
		||||
+	/* All modes support flow control */
 | 
			
		||||
+	state->supported |= SUPPORTED_Pause;
 | 
			
		||||
+	state->advertising |= ADVERTISED_Pause;
 | 
			
		||||
+
 | 
			
		||||
 	return 0;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										111
									
								
								target/linux/mvebu/patches-4.4/142-phylink-add-EEE-support.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								target/linux/mvebu/patches-4.4/142-phylink-add-EEE-support.patch
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,111 @@
 | 
			
		||||
From ffba226d73a2be262fff12d30aecf76d107b2ace Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
Date: Thu, 1 Oct 2015 21:19:53 +0100
 | 
			
		||||
Subject: [PATCH 730/744] phylink: add EEE support
 | 
			
		||||
 | 
			
		||||
Add EEE hooks to phylink to allow the phylib EEE functions for the
 | 
			
		||||
connected phy to be safely accessed.
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
---
 | 
			
		||||
 drivers/net/phy/phylink.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++-
 | 
			
		||||
 include/linux/phylink.h   |  7 +++++-
 | 
			
		||||
 2 files changed, 63 insertions(+), 2 deletions(-)
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/phy/phylink.c
 | 
			
		||||
+++ b/drivers/net/phy/phylink.c
 | 
			
		||||
@@ -334,7 +334,8 @@ static void phylink_resolve(struct work_
 | 
			
		||||
 			if (pl->phydev)
 | 
			
		||||
 				phylink_mac_config(pl, &link_state);
 | 
			
		||||
 
 | 
			
		||||
-			pl->ops->mac_link_up(ndev, pl->link_an_mode);
 | 
			
		||||
+			pl->ops->mac_link_up(ndev, pl->link_an_mode,
 | 
			
		||||
+					     pl->phydev);
 | 
			
		||||
 
 | 
			
		||||
 			netif_carrier_on(ndev);
 | 
			
		||||
 
 | 
			
		||||
@@ -818,6 +819,61 @@ int phylink_ethtool_set_pauseparam(struc
 | 
			
		||||
 }
 | 
			
		||||
 EXPORT_SYMBOL_GPL(phylink_ethtool_set_pauseparam);
 | 
			
		||||
 
 | 
			
		||||
+int phylink_init_eee(struct phylink *pl, bool clk_stop_enable)
 | 
			
		||||
+{
 | 
			
		||||
+	int ret = -EPROTONOSUPPORT;
 | 
			
		||||
+
 | 
			
		||||
+	mutex_lock(&pl->config_mutex);
 | 
			
		||||
+	if (pl->phydev)
 | 
			
		||||
+		ret = phy_init_eee(pl->phydev, clk_stop_enable);
 | 
			
		||||
+	mutex_unlock(&pl->config_mutex);
 | 
			
		||||
+
 | 
			
		||||
+	return ret;
 | 
			
		||||
+}
 | 
			
		||||
+EXPORT_SYMBOL_GPL(phylink_init_eee);
 | 
			
		||||
+
 | 
			
		||||
+int phylink_get_eee_err(struct phylink *pl)
 | 
			
		||||
+{
 | 
			
		||||
+	int ret = 0;
 | 
			
		||||
+
 | 
			
		||||
+	mutex_lock(&pl->config_mutex);
 | 
			
		||||
+	if (pl->phydev)
 | 
			
		||||
+		ret = phy_get_eee_err(pl->phydev);
 | 
			
		||||
+	mutex_unlock(&pl->config_mutex);
 | 
			
		||||
+
 | 
			
		||||
+	return ret;
 | 
			
		||||
+}
 | 
			
		||||
+EXPORT_SYMBOL_GPL(phylink_get_eee_err);
 | 
			
		||||
+
 | 
			
		||||
+int phylink_ethtool_get_eee(struct phylink *pl, struct ethtool_eee *eee)
 | 
			
		||||
+{
 | 
			
		||||
+	int ret = -EOPNOTSUPP;
 | 
			
		||||
+
 | 
			
		||||
+	mutex_lock(&pl->config_mutex);
 | 
			
		||||
+	if (pl->phydev)
 | 
			
		||||
+		ret = phy_ethtool_get_eee(pl->phydev, eee);
 | 
			
		||||
+	mutex_unlock(&pl->config_mutex);
 | 
			
		||||
+
 | 
			
		||||
+	return ret;
 | 
			
		||||
+}
 | 
			
		||||
+EXPORT_SYMBOL_GPL(phylink_ethtool_get_eee);
 | 
			
		||||
+
 | 
			
		||||
+int phylink_ethtool_set_eee(struct phylink *pl, struct ethtool_eee *eee)
 | 
			
		||||
+{
 | 
			
		||||
+	int ret = -EOPNOTSUPP;
 | 
			
		||||
+
 | 
			
		||||
+	mutex_lock(&pl->config_mutex);
 | 
			
		||||
+	if (pl->phydev) {
 | 
			
		||||
+		ret = phy_ethtool_set_eee(pl->phydev, eee);
 | 
			
		||||
+		if (ret == 0 && eee->eee_enabled)
 | 
			
		||||
+			phy_start_aneg(pl->phydev);
 | 
			
		||||
+	}
 | 
			
		||||
+	mutex_unlock(&pl->config_mutex);
 | 
			
		||||
+
 | 
			
		||||
+	return ret;
 | 
			
		||||
+}
 | 
			
		||||
+EXPORT_SYMBOL_GPL(phylink_ethtool_set_eee);
 | 
			
		||||
+
 | 
			
		||||
 /* This emulates MII registers for a fixed-mode phy operating as per the
 | 
			
		||||
  * passed in state. "aneg" defines if we report negotiation is possible.
 | 
			
		||||
  *
 | 
			
		||||
--- a/include/linux/phylink.h
 | 
			
		||||
+++ b/include/linux/phylink.h
 | 
			
		||||
@@ -51,7 +51,8 @@ struct phylink_mac_ops {
 | 
			
		||||
 	void (*mac_an_restart)(struct net_device *, unsigned int mode);
 | 
			
		||||
 
 | 
			
		||||
 	void (*mac_link_down)(struct net_device *, unsigned int mode);
 | 
			
		||||
-	void (*mac_link_up)(struct net_device *, unsigned int mode);
 | 
			
		||||
+	void (*mac_link_up)(struct net_device *, unsigned int mode,
 | 
			
		||||
+			    struct phy_device *);
 | 
			
		||||
 };
 | 
			
		||||
 
 | 
			
		||||
 struct phylink *phylink_create(struct net_device *, struct device_node *,
 | 
			
		||||
@@ -74,6 +75,10 @@ void phylink_ethtool_get_pauseparam(stru
 | 
			
		||||
 				    struct ethtool_pauseparam *);
 | 
			
		||||
 int phylink_ethtool_set_pauseparam(struct phylink *,
 | 
			
		||||
 				   struct ethtool_pauseparam *);
 | 
			
		||||
+int phylink_init_eee(struct phylink *, bool);
 | 
			
		||||
+int phylink_get_eee_err(struct phylink *);
 | 
			
		||||
+int phylink_ethtool_get_eee(struct phylink *, struct ethtool_eee *);
 | 
			
		||||
+int phylink_ethtool_set_eee(struct phylink *, struct ethtool_eee *);
 | 
			
		||||
 int phylink_mii_ioctl(struct phylink *, struct ifreq *, int);
 | 
			
		||||
 
 | 
			
		||||
 void phylink_set_link_port(struct phylink *pl, u32 support, u8 port);
 | 
			
		||||
@@ -0,0 +1,182 @@
 | 
			
		||||
From b7dacf514e41d6efff0ccc170f660cc6dc2aeae2 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
Date: Tue, 29 Sep 2015 15:17:39 +0100
 | 
			
		||||
Subject: [PATCH 731/744] net: mvneta: add EEE support
 | 
			
		||||
 | 
			
		||||
Add EEE support to mvneta.  This allows us to enable the low power idle
 | 
			
		||||
support at MAC level if there is a PHY attached through phylink which
 | 
			
		||||
supports LPI.  The appropriate ethtool support is provided to allow the
 | 
			
		||||
feature to be controlled, including ethtool statistics for EEE wakeup
 | 
			
		||||
errors.
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
---
 | 
			
		||||
 drivers/net/ethernet/marvell/mvneta.c | 87 +++++++++++++++++++++++++++++++++++
 | 
			
		||||
 1 file changed, 87 insertions(+)
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
+++ b/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
@@ -243,6 +243,12 @@
 | 
			
		||||
 #define MVNETA_TXQ_TOKEN_SIZE_REG(q)             (0x3e40 + ((q) << 2))
 | 
			
		||||
 #define      MVNETA_TXQ_TOKEN_SIZE_MAX           0x7fffffff
 | 
			
		||||
 
 | 
			
		||||
+#define MVNETA_LPI_CTRL_0                        0x2cc0
 | 
			
		||||
+#define MVNETA_LPI_CTRL_1                        0x2cc4
 | 
			
		||||
+#define      MVNETA_LPI_REQUEST_ENABLE           BIT(0)
 | 
			
		||||
+#define MVNETA_LPI_CTRL_2                        0x2cc8
 | 
			
		||||
+#define MVNETA_LPI_STATUS                        0x2ccc
 | 
			
		||||
+
 | 
			
		||||
 #define MVNETA_CAUSE_TXQ_SENT_DESC_ALL_MASK	 0xff
 | 
			
		||||
 
 | 
			
		||||
 /* Descriptor ring Macros */
 | 
			
		||||
@@ -316,6 +322,11 @@
 | 
			
		||||
 #define MVNETA_RX_GET_BM_POOL_ID(rxd) \
 | 
			
		||||
 	(((rxd)->status & MVNETA_RXD_BM_POOL_MASK) >> MVNETA_RXD_BM_POOL_SHIFT)
 | 
			
		||||
 
 | 
			
		||||
+enum {
 | 
			
		||||
+	ETHTOOL_STAT_EEE_WAKEUP,
 | 
			
		||||
+	ETHTOOL_MAX_STATS,
 | 
			
		||||
+};
 | 
			
		||||
+
 | 
			
		||||
 struct mvneta_statistic {
 | 
			
		||||
 	unsigned short offset;
 | 
			
		||||
 	unsigned short type;
 | 
			
		||||
@@ -324,6 +335,7 @@ struct mvneta_statistic {
 | 
			
		||||
 
 | 
			
		||||
 #define T_REG_32	32
 | 
			
		||||
 #define T_REG_64	64
 | 
			
		||||
+#define T_SW		1
 | 
			
		||||
 
 | 
			
		||||
 static const struct mvneta_statistic mvneta_statistics[] = {
 | 
			
		||||
 	{ 0x3000, T_REG_64, "good_octets_received", },
 | 
			
		||||
@@ -358,6 +370,7 @@ static const struct mvneta_statistic mvn
 | 
			
		||||
 	{ 0x304c, T_REG_32, "broadcast_frames_sent", },
 | 
			
		||||
 	{ 0x3054, T_REG_32, "fc_sent", },
 | 
			
		||||
 	{ 0x300c, T_REG_32, "internal_mac_transmit_err", },
 | 
			
		||||
+	{ ETHTOOL_STAT_EEE_WAKEUP, T_SW, "eee_wakeup_errors", },
 | 
			
		||||
 };
 | 
			
		||||
 
 | 
			
		||||
 struct mvneta_pcpu_stats {
 | 
			
		||||
@@ -413,6 +426,10 @@ struct mvneta_port {
 | 
			
		||||
 	struct mvneta_bm_pool *pool_short;
 | 
			
		||||
 	int bm_win_id;
 | 
			
		||||
 
 | 
			
		||||
+	bool eee_enabled;
 | 
			
		||||
+	bool eee_active;
 | 
			
		||||
+	bool tx_lpi_enabled;
 | 
			
		||||
+
 | 
			
		||||
 	u64 ethtool_stats[ARRAY_SIZE(mvneta_statistics)];
 | 
			
		||||
 
 | 
			
		||||
 	u32 indir[MVNETA_RSS_LU_TABLE_SIZE];
 | 
			
		||||
@@ -3276,6 +3293,18 @@ static void mvneta_mac_config(struct net
 | 
			
		||||
 		mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, new_an);
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
+static void mvneta_set_eee(struct mvneta_port *pp, bool enable)
 | 
			
		||||
+{
 | 
			
		||||
+	u32 lpi_ctl1;
 | 
			
		||||
+
 | 
			
		||||
+	lpi_ctl1 = mvreg_read(pp, MVNETA_LPI_CTRL_1);
 | 
			
		||||
+	if (enable)
 | 
			
		||||
+		lpi_ctl1 |= MVNETA_LPI_REQUEST_ENABLE;
 | 
			
		||||
+	else
 | 
			
		||||
+		lpi_ctl1 &= ~MVNETA_LPI_REQUEST_ENABLE;
 | 
			
		||||
+	mvreg_write(pp, MVNETA_LPI_CTRL_1, lpi_ctl1);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
 static void mvneta_mac_link_down(struct net_device *ndev, unsigned int mode)
 | 
			
		||||
 {
 | 
			
		||||
 	struct mvneta_port *pp = netdev_priv(ndev);
 | 
			
		||||
@@ -3289,6 +3318,9 @@ static void mvneta_mac_link_down(struct
 | 
			
		||||
 		val |= MVNETA_GMAC_FORCE_LINK_DOWN;
 | 
			
		||||
 		mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val);
 | 
			
		||||
 	}
 | 
			
		||||
+
 | 
			
		||||
+	pp->eee_active = false;
 | 
			
		||||
+	mvneta_set_eee(pp, false);
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
 static void mvneta_mac_link_up(struct net_device *ndev, unsigned int mode,
 | 
			
		||||
@@ -3305,6 +3337,11 @@ static void mvneta_mac_link_up(struct ne
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
 	mvneta_port_up(pp);
 | 
			
		||||
+
 | 
			
		||||
+	if (phy && pp->eee_enabled) {
 | 
			
		||||
+		pp->eee_active = phy_init_eee(phy, 0) >= 0;
 | 
			
		||||
+		mvneta_set_eee(pp, pp->eee_active && pp->tx_lpi_enabled);
 | 
			
		||||
+	}
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
 static const struct phylink_mac_ops mvneta_phylink_ops = {
 | 
			
		||||
@@ -3744,6 +3781,13 @@ static void mvneta_ethtool_update_stats(
 | 
			
		||||
 			val64 = (u64)high << 32 | low;
 | 
			
		||||
 			pp->ethtool_stats[i] += val64;
 | 
			
		||||
 			break;
 | 
			
		||||
+		case T_SW:
 | 
			
		||||
+			switch (s->offset) {
 | 
			
		||||
+			case ETHTOOL_STAT_EEE_WAKEUP:
 | 
			
		||||
+				val = phylink_get_eee_err(pp->phylink);
 | 
			
		||||
+				break;
 | 
			
		||||
+			}
 | 
			
		||||
+			break;
 | 
			
		||||
 		}
 | 
			
		||||
 	}
 | 
			
		||||
 }
 | 
			
		||||
@@ -3867,6 +3911,47 @@ static int mvneta_ethtool_get_rxfh(struc
 | 
			
		||||
 	return 0;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
+static int mvneta_ethtool_get_eee(struct net_device *dev,
 | 
			
		||||
+				  struct ethtool_eee *eee)
 | 
			
		||||
+{
 | 
			
		||||
+	struct mvneta_port *pp = netdev_priv(dev);
 | 
			
		||||
+	u32 lpi_ctl0;
 | 
			
		||||
+
 | 
			
		||||
+	lpi_ctl0 = mvreg_read(pp, MVNETA_LPI_CTRL_0);
 | 
			
		||||
+
 | 
			
		||||
+	eee->eee_enabled = pp->eee_enabled;
 | 
			
		||||
+	eee->eee_active = pp->eee_active;
 | 
			
		||||
+	eee->tx_lpi_enabled = pp->tx_lpi_enabled;
 | 
			
		||||
+	eee->tx_lpi_timer = (lpi_ctl0) >> 8; // * scale;
 | 
			
		||||
+
 | 
			
		||||
+	return phylink_ethtool_get_eee(pp->phylink, eee);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static int mvneta_ethtool_set_eee(struct net_device *dev,
 | 
			
		||||
+				  struct ethtool_eee *eee)
 | 
			
		||||
+{
 | 
			
		||||
+	struct mvneta_port *pp = netdev_priv(dev);
 | 
			
		||||
+	u32 lpi_ctl0;
 | 
			
		||||
+
 | 
			
		||||
+	/* The Armada 37x documents do not give limits for this other than
 | 
			
		||||
+	 * it being an 8-bit register. */
 | 
			
		||||
+	if (eee->tx_lpi_enabled &&
 | 
			
		||||
+	    (eee->tx_lpi_timer < 0 || eee->tx_lpi_timer > 255))
 | 
			
		||||
+		return -EINVAL;
 | 
			
		||||
+
 | 
			
		||||
+	lpi_ctl0 = mvreg_read(pp, MVNETA_LPI_CTRL_0);
 | 
			
		||||
+	lpi_ctl0 &= ~(0xff << 8);
 | 
			
		||||
+	lpi_ctl0 |= eee->tx_lpi_timer << 8;
 | 
			
		||||
+	mvreg_write(pp, MVNETA_LPI_CTRL_0, lpi_ctl0);
 | 
			
		||||
+
 | 
			
		||||
+	pp->eee_enabled = eee->eee_enabled;
 | 
			
		||||
+	pp->tx_lpi_enabled = eee->tx_lpi_enabled;
 | 
			
		||||
+
 | 
			
		||||
+	mvneta_set_eee(pp, eee->tx_lpi_enabled && eee->eee_enabled);
 | 
			
		||||
+
 | 
			
		||||
+	return phylink_ethtool_set_eee(pp->phylink, eee);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
 static const struct net_device_ops mvneta_netdev_ops = {
 | 
			
		||||
 	.ndo_open            = mvneta_open,
 | 
			
		||||
 	.ndo_stop            = mvneta_stop,
 | 
			
		||||
@@ -3898,6 +3983,8 @@ const struct ethtool_ops mvneta_eth_tool
 | 
			
		||||
 	.get_rxnfc	= mvneta_ethtool_get_rxnfc,
 | 
			
		||||
 	.get_rxfh	= mvneta_ethtool_get_rxfh,
 | 
			
		||||
 	.set_rxfh	= mvneta_ethtool_set_rxfh,
 | 
			
		||||
+	.get_eee	= mvneta_ethtool_get_eee,
 | 
			
		||||
+	.set_eee	= mvneta_ethtool_set_eee,
 | 
			
		||||
 };
 | 
			
		||||
 
 | 
			
		||||
 /* Initialize hw */
 | 
			
		||||
@@ -0,0 +1,137 @@
 | 
			
		||||
From 5419ccb638aa5c353ea88815e98953d9fc02e6ca Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
Date: Thu, 1 Oct 2015 23:10:05 +0100
 | 
			
		||||
Subject: [PATCH 732/744] phylink: add module EEPROM support
 | 
			
		||||
 | 
			
		||||
Add support for reading module EEPROMs through phylink.
 | 
			
		||||
 | 
			
		||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
 | 
			
		||||
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
---
 | 
			
		||||
 drivers/net/phy/phylink.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++
 | 
			
		||||
 include/linux/phylink.h   | 12 +++++++++
 | 
			
		||||
 2 files changed, 78 insertions(+)
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/phy/phylink.c
 | 
			
		||||
+++ b/drivers/net/phy/phylink.c
 | 
			
		||||
@@ -60,6 +60,9 @@ struct phylink {
 | 
			
		||||
 	struct work_struct resolve;
 | 
			
		||||
 
 | 
			
		||||
 	bool mac_link_up;
 | 
			
		||||
+
 | 
			
		||||
+	const struct phylink_module_ops *module_ops;
 | 
			
		||||
+	void *module_data;
 | 
			
		||||
 };
 | 
			
		||||
 
 | 
			
		||||
 static const char *phylink_an_mode_str(unsigned int mode)
 | 
			
		||||
@@ -819,6 +822,36 @@ int phylink_ethtool_set_pauseparam(struc
 | 
			
		||||
 }
 | 
			
		||||
 EXPORT_SYMBOL_GPL(phylink_ethtool_set_pauseparam);
 | 
			
		||||
 
 | 
			
		||||
+int phylink_ethtool_get_module_info(struct phylink *pl,
 | 
			
		||||
+				    struct ethtool_modinfo *modinfo)
 | 
			
		||||
+{
 | 
			
		||||
+	int ret = -EOPNOTSUPP;
 | 
			
		||||
+
 | 
			
		||||
+	mutex_lock(&pl->config_mutex);
 | 
			
		||||
+	if (pl->module_ops)
 | 
			
		||||
+		ret = pl->module_ops->get_module_info(pl->module_data,
 | 
			
		||||
+						      modinfo);
 | 
			
		||||
+	mutex_unlock(&pl->config_mutex);
 | 
			
		||||
+
 | 
			
		||||
+	return ret;
 | 
			
		||||
+}
 | 
			
		||||
+EXPORT_SYMBOL_GPL(phylink_ethtool_get_module_info);
 | 
			
		||||
+
 | 
			
		||||
+int phylink_ethtool_get_module_eeprom(struct phylink *pl,
 | 
			
		||||
+				      struct ethtool_eeprom *ee, u8 *buf)
 | 
			
		||||
+{
 | 
			
		||||
+	int ret = -EOPNOTSUPP;
 | 
			
		||||
+
 | 
			
		||||
+	mutex_lock(&pl->config_mutex);
 | 
			
		||||
+	if (pl->module_ops)
 | 
			
		||||
+		ret = pl->module_ops->get_module_eeprom(pl->module_data, ee,
 | 
			
		||||
+							buf);
 | 
			
		||||
+	mutex_unlock(&pl->config_mutex);
 | 
			
		||||
+
 | 
			
		||||
+	return ret;
 | 
			
		||||
+}
 | 
			
		||||
+EXPORT_SYMBOL_GPL(phylink_ethtool_get_module_eeprom);
 | 
			
		||||
+
 | 
			
		||||
 int phylink_init_eee(struct phylink *pl, bool clk_stop_enable)
 | 
			
		||||
 {
 | 
			
		||||
 	int ret = -EPROTONOSUPPORT;
 | 
			
		||||
@@ -1016,6 +1049,39 @@ EXPORT_SYMBOL_GPL(phylink_mii_ioctl);
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
+int phylink_register_module(struct phylink *pl, void *data,
 | 
			
		||||
+			    const struct phylink_module_ops *ops)
 | 
			
		||||
+{
 | 
			
		||||
+	int ret = -EBUSY;
 | 
			
		||||
+
 | 
			
		||||
+	mutex_lock(&pl->config_mutex);
 | 
			
		||||
+	if (!pl->module_ops) {
 | 
			
		||||
+		pl->module_ops = ops;
 | 
			
		||||
+		pl->module_data = data;
 | 
			
		||||
+		ret = 0;
 | 
			
		||||
+	}
 | 
			
		||||
+	mutex_unlock(&pl->config_mutex);
 | 
			
		||||
+
 | 
			
		||||
+	return ret;
 | 
			
		||||
+}
 | 
			
		||||
+EXPORT_SYMBOL_GPL(phylink_register_module);
 | 
			
		||||
+
 | 
			
		||||
+int phylink_unregister_module(struct phylink *pl, void *data)
 | 
			
		||||
+{
 | 
			
		||||
+	int ret = -EINVAL;
 | 
			
		||||
+
 | 
			
		||||
+	mutex_lock(&pl->config_mutex);
 | 
			
		||||
+	if (pl->module_data == data) {
 | 
			
		||||
+		pl->module_ops = NULL;
 | 
			
		||||
+		pl->module_data = NULL;
 | 
			
		||||
+		ret = 0;
 | 
			
		||||
+	}
 | 
			
		||||
+	mutex_unlock(&pl->config_mutex);
 | 
			
		||||
+
 | 
			
		||||
+	return ret;
 | 
			
		||||
+}
 | 
			
		||||
+EXPORT_SYMBOL_GPL(phylink_unregister_module);
 | 
			
		||||
+
 | 
			
		||||
 void phylink_disable(struct phylink *pl)
 | 
			
		||||
 {
 | 
			
		||||
 	set_bit(PHYLINK_DISABLE_LINK, &pl->phylink_disable_state);
 | 
			
		||||
--- a/include/linux/phylink.h
 | 
			
		||||
+++ b/include/linux/phylink.h
 | 
			
		||||
@@ -55,6 +55,11 @@ struct phylink_mac_ops {
 | 
			
		||||
 			    struct phy_device *);
 | 
			
		||||
 };
 | 
			
		||||
 
 | 
			
		||||
+struct phylink_module_ops {
 | 
			
		||||
+	int (*get_module_info)(void *, struct ethtool_modinfo *);
 | 
			
		||||
+	int (*get_module_eeprom)(void *, struct ethtool_eeprom *, u8 *);
 | 
			
		||||
+};
 | 
			
		||||
+
 | 
			
		||||
 struct phylink *phylink_create(struct net_device *, struct device_node *,
 | 
			
		||||
 	phy_interface_t iface, const struct phylink_mac_ops *ops);
 | 
			
		||||
 void phylink_destroy(struct phylink *);
 | 
			
		||||
@@ -75,12 +80,19 @@ void phylink_ethtool_get_pauseparam(stru
 | 
			
		||||
 				    struct ethtool_pauseparam *);
 | 
			
		||||
 int phylink_ethtool_set_pauseparam(struct phylink *,
 | 
			
		||||
 				   struct ethtool_pauseparam *);
 | 
			
		||||
+int phylink_ethtool_get_module_info(struct phylink *, struct ethtool_modinfo *);
 | 
			
		||||
+int phylink_ethtool_get_module_eeprom(struct phylink *,
 | 
			
		||||
+				      struct ethtool_eeprom *, u8 *);
 | 
			
		||||
 int phylink_init_eee(struct phylink *, bool);
 | 
			
		||||
 int phylink_get_eee_err(struct phylink *);
 | 
			
		||||
 int phylink_ethtool_get_eee(struct phylink *, struct ethtool_eee *);
 | 
			
		||||
 int phylink_ethtool_set_eee(struct phylink *, struct ethtool_eee *);
 | 
			
		||||
 int phylink_mii_ioctl(struct phylink *, struct ifreq *, int);
 | 
			
		||||
 
 | 
			
		||||
+int phylink_register_module(struct phylink *, void *,
 | 
			
		||||
+			    const struct phylink_module_ops *);
 | 
			
		||||
+int phylink_unregister_module(struct phylink *, void *);
 | 
			
		||||
+
 | 
			
		||||
 void phylink_set_link_port(struct phylink *pl, u32 support, u8 port);
 | 
			
		||||
 int phylink_set_link_an_mode(struct phylink *pl, unsigned int mode);
 | 
			
		||||
 void phylink_disable(struct phylink *pl);
 | 
			
		||||
@@ -0,0 +1,44 @@
 | 
			
		||||
From 665e1fe77dedcfc6b5669214ebfd252c803290d4 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
Date: Thu, 1 Oct 2015 23:32:39 +0100
 | 
			
		||||
Subject: [PATCH 733/744] net: mvneta: add module EEPROM reading support
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
---
 | 
			
		||||
 drivers/net/ethernet/marvell/mvneta.c | 18 ++++++++++++++++++
 | 
			
		||||
 1 file changed, 18 insertions(+)
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
+++ b/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
@@ -3911,6 +3911,22 @@ static int mvneta_ethtool_get_rxfh(struc
 | 
			
		||||
 	return 0;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
+static int mvneta_ethtool_get_module_info(struct net_device *dev,
 | 
			
		||||
+					  struct ethtool_modinfo *modinfo)
 | 
			
		||||
+{
 | 
			
		||||
+	struct mvneta_port *pp = netdev_priv(dev);
 | 
			
		||||
+
 | 
			
		||||
+	return phylink_ethtool_get_module_info(pp->phylink, modinfo);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static int mvneta_ethtool_get_module_eeprom(struct net_device *dev,
 | 
			
		||||
+					    struct ethtool_eeprom *ee, u8 *buf)
 | 
			
		||||
+{
 | 
			
		||||
+	struct mvneta_port *pp = netdev_priv(dev);
 | 
			
		||||
+
 | 
			
		||||
+	return phylink_ethtool_get_module_eeprom(pp->phylink, ee, buf);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
 static int mvneta_ethtool_get_eee(struct net_device *dev,
 | 
			
		||||
 				  struct ethtool_eee *eee)
 | 
			
		||||
 {
 | 
			
		||||
@@ -3983,6 +3999,8 @@ const struct ethtool_ops mvneta_eth_tool
 | 
			
		||||
 	.get_rxnfc	= mvneta_ethtool_get_rxnfc,
 | 
			
		||||
 	.get_rxfh	= mvneta_ethtool_get_rxfh,
 | 
			
		||||
 	.set_rxfh	= mvneta_ethtool_set_rxfh,
 | 
			
		||||
+	.get_module_info = mvneta_ethtool_get_module_info,
 | 
			
		||||
+	.get_module_eeprom = mvneta_ethtool_get_module_eeprom,
 | 
			
		||||
 	.get_eee	= mvneta_ethtool_get_eee,
 | 
			
		||||
 	.set_eee	= mvneta_ethtool_set_eee,
 | 
			
		||||
 };
 | 
			
		||||
@@ -0,0 +1,68 @@
 | 
			
		||||
From a7091ef24223ed39b39c6b73b77c55c8a607f34a Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
Date: Thu, 8 Oct 2015 23:49:47 +0100
 | 
			
		||||
Subject: [PATCH 734/744] sfp/phylink: hook up eeprom functions
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
---
 | 
			
		||||
 drivers/net/phy/sfp.c | 19 +++++++++++--------
 | 
			
		||||
 1 file changed, 11 insertions(+), 8 deletions(-)
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/phy/sfp.c
 | 
			
		||||
+++ b/drivers/net/phy/sfp.c
 | 
			
		||||
@@ -901,11 +901,9 @@ static void sfp_sm_event(struct sfp *sfp
 | 
			
		||||
 	mutex_unlock(&sfp->sm_mutex);
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
-#if 0
 | 
			
		||||
-static int sfp_phy_module_info(struct phy_device *phy,
 | 
			
		||||
-			       struct ethtool_modinfo *modinfo)
 | 
			
		||||
+static int sfp_module_info(void *priv, struct ethtool_modinfo *modinfo)
 | 
			
		||||
 {
 | 
			
		||||
-	struct sfp *sfp = phy->priv;
 | 
			
		||||
+	struct sfp *sfp = priv;
 | 
			
		||||
 
 | 
			
		||||
 	/* locking... and check module is present */
 | 
			
		||||
 
 | 
			
		||||
@@ -919,10 +917,9 @@ static int sfp_phy_module_info(struct ph
 | 
			
		||||
 	return 0;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
-static int sfp_phy_module_eeprom(struct phy_device *phy,
 | 
			
		||||
-	struct ethtool_eeprom *ee, u8 *data)
 | 
			
		||||
+static int sfp_module_eeprom(void *priv, struct ethtool_eeprom *ee, u8 *data)
 | 
			
		||||
 {
 | 
			
		||||
-	struct sfp *sfp = phy->priv;
 | 
			
		||||
+	struct sfp *sfp = priv;
 | 
			
		||||
 	unsigned int first, last, len;
 | 
			
		||||
 	int ret;
 | 
			
		||||
 
 | 
			
		||||
@@ -953,7 +950,11 @@ static int sfp_phy_module_eeprom(struct
 | 
			
		||||
 	}
 | 
			
		||||
 	return 0;
 | 
			
		||||
 }
 | 
			
		||||
-#endif
 | 
			
		||||
+
 | 
			
		||||
+static const struct phylink_module_ops sfp_module_ops = {
 | 
			
		||||
+	.get_module_info = sfp_module_info,
 | 
			
		||||
+	.get_module_eeprom = sfp_module_eeprom,
 | 
			
		||||
+};
 | 
			
		||||
 
 | 
			
		||||
 static void sfp_timeout(struct work_struct *work)
 | 
			
		||||
 {
 | 
			
		||||
@@ -1029,6 +1030,7 @@ static int sfp_netdev_notify(struct noti
 | 
			
		||||
 	case NETDEV_UNREGISTER:
 | 
			
		||||
 		if (sfp->mod_phy && sfp->phylink)
 | 
			
		||||
 			phylink_disconnect_phy(sfp->phylink);
 | 
			
		||||
+		phylink_unregister_module(sfp->phylink, sfp);
 | 
			
		||||
 		sfp->phylink = NULL;
 | 
			
		||||
 		dev_put(sfp->ndev);
 | 
			
		||||
 		sfp->ndev = NULL;
 | 
			
		||||
@@ -1145,6 +1147,7 @@ static int sfp_probe(struct platform_dev
 | 
			
		||||
 		}
 | 
			
		||||
 
 | 
			
		||||
 		phylink_disable(sfp->phylink);
 | 
			
		||||
+		phylink_register_module(sfp->phylink, sfp, &sfp_module_ops);
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
 	sfp->state = sfp_get_state(sfp);
 | 
			
		||||
@@ -0,0 +1,83 @@
 | 
			
		||||
--- a/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
+++ b/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
@@ -1695,8 +1695,10 @@ static struct mvneta_tx_queue *mvneta_tx
 | 
			
		||||
 
 | 
			
		||||
 /* Free tx queue skbuffs */
 | 
			
		||||
 static void mvneta_txq_bufs_free(struct mvneta_port *pp,
 | 
			
		||||
-				 struct mvneta_tx_queue *txq, int num)
 | 
			
		||||
+				 struct mvneta_tx_queue *txq, int num,
 | 
			
		||||
+				 struct netdev_queue *nq)
 | 
			
		||||
 {
 | 
			
		||||
+	unsigned int bytes_compl = 0, pkts_compl = 0;
 | 
			
		||||
 	int i;
 | 
			
		||||
 
 | 
			
		||||
 	for (i = 0; i < num; i++) {
 | 
			
		||||
@@ -1704,6 +1706,11 @@ static void mvneta_txq_bufs_free(struct
 | 
			
		||||
 			txq->txq_get_index;
 | 
			
		||||
 		struct sk_buff *skb = txq->tx_skb[txq->txq_get_index];
 | 
			
		||||
 
 | 
			
		||||
+		if (skb) {
 | 
			
		||||
+			bytes_compl += skb->len;
 | 
			
		||||
+			pkts_compl++;
 | 
			
		||||
+		}
 | 
			
		||||
+
 | 
			
		||||
 		mvneta_txq_inc_get(txq);
 | 
			
		||||
 
 | 
			
		||||
 		if (!IS_TSO_HEADER(txq, tx_desc->buf_phys_addr))
 | 
			
		||||
@@ -1714,6 +1721,8 @@ static void mvneta_txq_bufs_free(struct
 | 
			
		||||
 			continue;
 | 
			
		||||
 		dev_kfree_skb_any(skb);
 | 
			
		||||
 	}
 | 
			
		||||
+
 | 
			
		||||
+	netdev_tx_completed_queue(nq, pkts_compl, bytes_compl);
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
 /* Handle end of transmission */
 | 
			
		||||
@@ -1727,7 +1736,7 @@ static void mvneta_txq_done(struct mvnet
 | 
			
		||||
 	if (!tx_done)
 | 
			
		||||
 		return;
 | 
			
		||||
 
 | 
			
		||||
-	mvneta_txq_bufs_free(pp, txq, tx_done);
 | 
			
		||||
+	mvneta_txq_bufs_free(pp, txq, tx_done, nq);
 | 
			
		||||
 
 | 
			
		||||
 	txq->count -= tx_done;
 | 
			
		||||
 
 | 
			
		||||
@@ -2334,6 +2343,8 @@ out:
 | 
			
		||||
 		struct mvneta_pcpu_stats *stats = this_cpu_ptr(pp->stats);
 | 
			
		||||
 		struct netdev_queue *nq = netdev_get_tx_queue(dev, txq_id);
 | 
			
		||||
 
 | 
			
		||||
+		netdev_tx_sent_queue(nq, len);
 | 
			
		||||
+
 | 
			
		||||
 		txq->count += frags;
 | 
			
		||||
 		mvneta_txq_pend_desc_add(pp, txq, frags);
 | 
			
		||||
 
 | 
			
		||||
@@ -2358,9 +2369,10 @@ static void mvneta_txq_done_force(struct
 | 
			
		||||
 				  struct mvneta_tx_queue *txq)
 | 
			
		||||
 
 | 
			
		||||
 {
 | 
			
		||||
+	struct netdev_queue *nq = netdev_get_tx_queue(pp->dev, txq->id);
 | 
			
		||||
 	int tx_done = txq->count;
 | 
			
		||||
 
 | 
			
		||||
-	mvneta_txq_bufs_free(pp, txq, tx_done);
 | 
			
		||||
+	mvneta_txq_bufs_free(pp, txq, tx_done, nq);
 | 
			
		||||
 
 | 
			
		||||
 	/* reset txq */
 | 
			
		||||
 	txq->count = 0;
 | 
			
		||||
@@ -2841,6 +2853,8 @@ static int mvneta_txq_init(struct mvneta
 | 
			
		||||
 static void mvneta_txq_deinit(struct mvneta_port *pp,
 | 
			
		||||
 			      struct mvneta_tx_queue *txq)
 | 
			
		||||
 {
 | 
			
		||||
+	struct netdev_queue *nq = netdev_get_tx_queue(pp->dev, txq->id);
 | 
			
		||||
+
 | 
			
		||||
 	kfree(txq->tx_skb);
 | 
			
		||||
 
 | 
			
		||||
 	if (txq->tso_hdrs)
 | 
			
		||||
@@ -2852,6 +2866,8 @@ static void mvneta_txq_deinit(struct mvn
 | 
			
		||||
 				  txq->size * MVNETA_DESC_ALIGNED_SIZE,
 | 
			
		||||
 				  txq->descs, txq->descs_phys);
 | 
			
		||||
 
 | 
			
		||||
+	netdev_tx_reset_queue(nq);
 | 
			
		||||
+
 | 
			
		||||
 	txq->descs             = NULL;
 | 
			
		||||
 	txq->last_desc         = 0;
 | 
			
		||||
 	txq->next_desc_to_proc = 0;
 | 
			
		||||
@@ -0,0 +1,433 @@
 | 
			
		||||
Armada 370/XP devices can 'blink' gpio lines with a configurable on
 | 
			
		||||
and off period. This can be modelled as a PWM.
 | 
			
		||||
 | 
			
		||||
However, there are only two sets of PWM configuration registers for
 | 
			
		||||
all the gpio lines. This driver simply allows a single gpio line per
 | 
			
		||||
gpio chip of 32 lines to be used as a PWM. Attempts to use more return
 | 
			
		||||
EBUSY.
 | 
			
		||||
 | 
			
		||||
Due to the interleaving of registers it is not simple to separate the
 | 
			
		||||
PWM driver from the gpio driver. Thus the gpio driver has been
 | 
			
		||||
extended with a PWM driver.
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
 | 
			
		||||
---
 | 
			
		||||
 drivers/gpio/Kconfig          |   5 ++
 | 
			
		||||
 drivers/gpio/Makefile         |   1 +
 | 
			
		||||
 drivers/gpio/gpio-mvebu-pwm.c | 202 ++++++++++++++++++++++++++++++++++++++++++
 | 
			
		||||
 drivers/gpio/gpio-mvebu.c     |  37 +++-----
 | 
			
		||||
 drivers/gpio/gpio-mvebu.h     |  79 +++++++++++++++++
 | 
			
		||||
 5 files changed, 299 insertions(+), 25 deletions(-)
 | 
			
		||||
 create mode 100644 drivers/gpio/gpio-mvebu-pwm.c
 | 
			
		||||
 create mode 100644 drivers/gpio/gpio-mvebu.h
 | 
			
		||||
 | 
			
		||||
--- a/drivers/gpio/Kconfig
 | 
			
		||||
+++ b/drivers/gpio/Kconfig
 | 
			
		||||
@@ -295,6 +295,11 @@ config GPIO_MVEBU
 | 
			
		||||
 	depends on OF
 | 
			
		||||
 	select GENERIC_IRQ_CHIP
 | 
			
		||||
 
 | 
			
		||||
+config GPIO_MVEBU_PWM
 | 
			
		||||
+	def_bool y
 | 
			
		||||
+	depends on GPIO_MVEBU
 | 
			
		||||
+	depends on PWM
 | 
			
		||||
+
 | 
			
		||||
 config GPIO_MXC
 | 
			
		||||
 	def_bool y
 | 
			
		||||
 	depends on ARCH_MXC
 | 
			
		||||
--- a/drivers/gpio/Makefile
 | 
			
		||||
+++ b/drivers/gpio/Makefile
 | 
			
		||||
@@ -67,6 +67,7 @@ obj-$(CONFIG_GPIO_MPC5200)	+= gpio-mpc52
 | 
			
		||||
 obj-$(CONFIG_GPIO_MPC8XXX)	+= gpio-mpc8xxx.o
 | 
			
		||||
 obj-$(CONFIG_GPIO_MSIC)		+= gpio-msic.o
 | 
			
		||||
 obj-$(CONFIG_GPIO_MVEBU)        += gpio-mvebu.o
 | 
			
		||||
+obj-$(CONFIG_GPIO_MVEBU_PWM)	+= gpio-mvebu-pwm.o
 | 
			
		||||
 obj-$(CONFIG_GPIO_MXC)		+= gpio-mxc.o
 | 
			
		||||
 obj-$(CONFIG_GPIO_MXS)		+= gpio-mxs.o
 | 
			
		||||
 obj-$(CONFIG_GPIO_OCTEON)	+= gpio-octeon.o
 | 
			
		||||
--- /dev/null
 | 
			
		||||
+++ b/drivers/gpio/gpio-mvebu-pwm.c
 | 
			
		||||
@@ -0,0 +1,202 @@
 | 
			
		||||
+#include <linux/err.h>
 | 
			
		||||
+#include <linux/module.h>
 | 
			
		||||
+#include <linux/gpio.h>
 | 
			
		||||
+#include <linux/pwm.h>
 | 
			
		||||
+#include <linux/clk.h>
 | 
			
		||||
+#include <linux/platform_device.h>
 | 
			
		||||
+#include "gpio-mvebu.h"
 | 
			
		||||
+#include "gpiolib.h"
 | 
			
		||||
+
 | 
			
		||||
+static void __iomem *mvebu_gpioreg_blink_select(struct mvebu_gpio_chip *mvchip)
 | 
			
		||||
+{
 | 
			
		||||
+	return mvchip->membase + GPIO_BLINK_CNT_SELECT;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static inline struct mvebu_pwm *to_mvebu_pwm(struct pwm_chip *chip)
 | 
			
		||||
+{
 | 
			
		||||
+	return container_of(chip, struct mvebu_pwm, chip);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static inline struct mvebu_gpio_chip *to_mvchip(struct mvebu_pwm *pwm)
 | 
			
		||||
+{
 | 
			
		||||
+	return container_of(pwm, struct mvebu_gpio_chip, pwm);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static int mvebu_pwm_request(struct pwm_chip *chip, struct pwm_device *pwmd)
 | 
			
		||||
+{
 | 
			
		||||
+	struct mvebu_pwm *pwm = to_mvebu_pwm(chip);
 | 
			
		||||
+	struct mvebu_gpio_chip *mvchip = to_mvchip(pwm);
 | 
			
		||||
+	struct gpio_desc *desc = gpio_to_desc(pwmd->pwm);
 | 
			
		||||
+	unsigned long flags;
 | 
			
		||||
+	int ret = 0;
 | 
			
		||||
+
 | 
			
		||||
+	spin_lock_irqsave(&pwm->lock, flags);
 | 
			
		||||
+	if (pwm->used) {
 | 
			
		||||
+		ret = -EBUSY;
 | 
			
		||||
+	} else {
 | 
			
		||||
+		if (!desc) {
 | 
			
		||||
+			ret = -ENODEV;
 | 
			
		||||
+			goto out;
 | 
			
		||||
+		}
 | 
			
		||||
+		ret = gpiod_request(desc, "mvebu-pwm");
 | 
			
		||||
+		if (ret)
 | 
			
		||||
+			goto out;
 | 
			
		||||
+
 | 
			
		||||
+		ret = gpiod_direction_output(desc, 0);
 | 
			
		||||
+		if (ret) {
 | 
			
		||||
+			gpiod_free(desc);
 | 
			
		||||
+			goto out;
 | 
			
		||||
+		}
 | 
			
		||||
+
 | 
			
		||||
+		pwm->pin = pwmd->pwm - mvchip->chip.base;
 | 
			
		||||
+		pwm->used = true;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+out:
 | 
			
		||||
+	spin_unlock_irqrestore(&pwm->lock, flags);
 | 
			
		||||
+	return ret;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static void mvebu_pwm_free(struct pwm_chip *chip, struct pwm_device *pwmd)
 | 
			
		||||
+{
 | 
			
		||||
+	struct mvebu_pwm *pwm = to_mvebu_pwm(chip);
 | 
			
		||||
+	struct gpio_desc *desc = gpio_to_desc(pwmd->pwm);
 | 
			
		||||
+	unsigned long flags;
 | 
			
		||||
+
 | 
			
		||||
+	spin_lock_irqsave(&pwm->lock, flags);
 | 
			
		||||
+	gpiod_free(desc);
 | 
			
		||||
+	pwm->used = false;
 | 
			
		||||
+	spin_unlock_irqrestore(&pwm->lock, flags);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static int mvebu_pwm_config(struct pwm_chip *chip, struct pwm_device *pwmd,
 | 
			
		||||
+			    int duty_ns, int period_ns)
 | 
			
		||||
+{
 | 
			
		||||
+	struct mvebu_pwm *pwm = to_mvebu_pwm(chip);
 | 
			
		||||
+	struct mvebu_gpio_chip *mvchip = to_mvchip(pwm);
 | 
			
		||||
+	unsigned int on, off;
 | 
			
		||||
+	unsigned long long val;
 | 
			
		||||
+	u32 u;
 | 
			
		||||
+
 | 
			
		||||
+	val = (unsigned long long) pwm->clk_rate * duty_ns;
 | 
			
		||||
+	do_div(val, NSEC_PER_SEC);
 | 
			
		||||
+	if (val > UINT_MAX)
 | 
			
		||||
+		return -EINVAL;
 | 
			
		||||
+	if (val)
 | 
			
		||||
+		on = val;
 | 
			
		||||
+	else
 | 
			
		||||
+		on = 1;
 | 
			
		||||
+
 | 
			
		||||
+	val = (unsigned long long) pwm->clk_rate * (period_ns - duty_ns);
 | 
			
		||||
+	do_div(val, NSEC_PER_SEC);
 | 
			
		||||
+	if (val > UINT_MAX)
 | 
			
		||||
+		return -EINVAL;
 | 
			
		||||
+	if (val)
 | 
			
		||||
+		off = val;
 | 
			
		||||
+	else
 | 
			
		||||
+		off = 1;
 | 
			
		||||
+
 | 
			
		||||
+	u = readl_relaxed(mvebu_gpioreg_blink_select(mvchip));
 | 
			
		||||
+	u &= ~(1 << pwm->pin);
 | 
			
		||||
+	u |= (pwm->id << pwm->pin);
 | 
			
		||||
+	writel_relaxed(u, mvebu_gpioreg_blink_select(mvchip));
 | 
			
		||||
+
 | 
			
		||||
+	writel_relaxed(on, pwm->membase + BLINK_ON_DURATION);
 | 
			
		||||
+	writel_relaxed(off, pwm->membase + BLINK_OFF_DURATION);
 | 
			
		||||
+
 | 
			
		||||
+	return 0;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static int mvebu_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwmd)
 | 
			
		||||
+{
 | 
			
		||||
+	struct mvebu_pwm *pwm = to_mvebu_pwm(chip);
 | 
			
		||||
+	struct mvebu_gpio_chip *mvchip = to_mvchip(pwm);
 | 
			
		||||
+
 | 
			
		||||
+	mvebu_gpio_blink(&mvchip->chip, pwm->pin, 1);
 | 
			
		||||
+
 | 
			
		||||
+	return 0;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static void mvebu_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwmd)
 | 
			
		||||
+{
 | 
			
		||||
+	struct mvebu_pwm *pwm = to_mvebu_pwm(chip);
 | 
			
		||||
+	struct mvebu_gpio_chip *mvchip = to_mvchip(pwm);
 | 
			
		||||
+
 | 
			
		||||
+	mvebu_gpio_blink(&mvchip->chip, pwm->pin, 0);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static const struct pwm_ops mvebu_pwm_ops = {
 | 
			
		||||
+	.request = mvebu_pwm_request,
 | 
			
		||||
+	.free = mvebu_pwm_free,
 | 
			
		||||
+	.config = mvebu_pwm_config,
 | 
			
		||||
+	.enable = mvebu_pwm_enable,
 | 
			
		||||
+	.disable = mvebu_pwm_disable,
 | 
			
		||||
+	.owner = THIS_MODULE,
 | 
			
		||||
+};
 | 
			
		||||
+
 | 
			
		||||
+void mvebu_pwm_suspend(struct mvebu_gpio_chip *mvchip)
 | 
			
		||||
+{
 | 
			
		||||
+	struct mvebu_pwm *pwm = &mvchip->pwm;
 | 
			
		||||
+
 | 
			
		||||
+	pwm->blink_select = readl_relaxed(mvebu_gpioreg_blink_select(mvchip));
 | 
			
		||||
+	pwm->blink_on_duration =
 | 
			
		||||
+		readl_relaxed(pwm->membase + BLINK_ON_DURATION);
 | 
			
		||||
+	pwm->blink_off_duration =
 | 
			
		||||
+		readl_relaxed(pwm->membase + BLINK_OFF_DURATION);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+void mvebu_pwm_resume(struct mvebu_gpio_chip *mvchip)
 | 
			
		||||
+{
 | 
			
		||||
+	struct mvebu_pwm *pwm = &mvchip->pwm;
 | 
			
		||||
+
 | 
			
		||||
+	writel_relaxed(pwm->blink_select, mvebu_gpioreg_blink_select(mvchip));
 | 
			
		||||
+	writel_relaxed(pwm->blink_on_duration,
 | 
			
		||||
+		       pwm->membase + BLINK_ON_DURATION);
 | 
			
		||||
+	writel_relaxed(pwm->blink_off_duration,
 | 
			
		||||
+		       pwm->membase + BLINK_OFF_DURATION);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+/*
 | 
			
		||||
+ * Armada 370/XP has simple PWM support for gpio lines. Other SoCs
 | 
			
		||||
+ * don't have this hardware. So if we don't have the necessary
 | 
			
		||||
+ * resource, it is not an error.
 | 
			
		||||
+ */
 | 
			
		||||
+int mvebu_pwm_probe(struct platform_device *pdev,
 | 
			
		||||
+		    struct mvebu_gpio_chip *mvchip,
 | 
			
		||||
+		    int id)
 | 
			
		||||
+{
 | 
			
		||||
+	struct device *dev = &pdev->dev;
 | 
			
		||||
+	struct mvebu_pwm *pwm = &mvchip->pwm;
 | 
			
		||||
+	struct resource *res;
 | 
			
		||||
+
 | 
			
		||||
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pwm");
 | 
			
		||||
+	if (!res)
 | 
			
		||||
+		return 0;
 | 
			
		||||
+
 | 
			
		||||
+	mvchip->pwm.membase = devm_ioremap_resource(&pdev->dev, res);
 | 
			
		||||
+	if (IS_ERR(mvchip->pwm.membase))
 | 
			
		||||
+		return PTR_ERR(mvchip->percpu_membase);
 | 
			
		||||
+
 | 
			
		||||
+	if (id < 0 || id > 1)
 | 
			
		||||
+		return -EINVAL;
 | 
			
		||||
+	pwm->id = id;
 | 
			
		||||
+
 | 
			
		||||
+	if (IS_ERR(mvchip->clk))
 | 
			
		||||
+		return PTR_ERR(mvchip->clk);
 | 
			
		||||
+
 | 
			
		||||
+	pwm->clk_rate = clk_get_rate(mvchip->clk);
 | 
			
		||||
+	if (!pwm->clk_rate) {
 | 
			
		||||
+		dev_err(dev, "failed to get clock rate\n");
 | 
			
		||||
+		return -EINVAL;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	pwm->chip.dev = dev;
 | 
			
		||||
+	pwm->chip.ops = &mvebu_pwm_ops;
 | 
			
		||||
+	pwm->chip.base = mvchip->chip.base;
 | 
			
		||||
+	pwm->chip.npwm = mvchip->chip.ngpio;
 | 
			
		||||
+	pwm->chip.can_sleep = false;
 | 
			
		||||
+
 | 
			
		||||
+	spin_lock_init(&pwm->lock);
 | 
			
		||||
+
 | 
			
		||||
+	return pwmchip_add(&pwm->chip);
 | 
			
		||||
+}
 | 
			
		||||
--- a/drivers/gpio/gpio-mvebu.c
 | 
			
		||||
+++ b/drivers/gpio/gpio-mvebu.c
 | 
			
		||||
@@ -42,10 +42,11 @@
 | 
			
		||||
 #include <linux/io.h>
 | 
			
		||||
 #include <linux/of_irq.h>
 | 
			
		||||
 #include <linux/of_device.h>
 | 
			
		||||
+#include <linux/pwm.h>
 | 
			
		||||
 #include <linux/clk.h>
 | 
			
		||||
 #include <linux/pinctrl/consumer.h>
 | 
			
		||||
 #include <linux/irqchip/chained_irq.h>
 | 
			
		||||
-
 | 
			
		||||
+#include "gpio-mvebu.h"
 | 
			
		||||
 /*
 | 
			
		||||
  * GPIO unit register offsets.
 | 
			
		||||
  */
 | 
			
		||||
@@ -75,24 +76,6 @@
 | 
			
		||||
 
 | 
			
		||||
 #define MVEBU_MAX_GPIO_PER_BANK		32
 | 
			
		||||
 
 | 
			
		||||
-struct mvebu_gpio_chip {
 | 
			
		||||
-	struct gpio_chip   chip;
 | 
			
		||||
-	spinlock_t	   lock;
 | 
			
		||||
-	void __iomem	  *membase;
 | 
			
		||||
-	void __iomem	  *percpu_membase;
 | 
			
		||||
-	int		   irqbase;
 | 
			
		||||
-	struct irq_domain *domain;
 | 
			
		||||
-	int		   soc_variant;
 | 
			
		||||
-
 | 
			
		||||
-	/* Used to preserve GPIO registers across suspend/resume */
 | 
			
		||||
-	u32                out_reg;
 | 
			
		||||
-	u32                io_conf_reg;
 | 
			
		||||
-	u32                blink_en_reg;
 | 
			
		||||
-	u32                in_pol_reg;
 | 
			
		||||
-	u32                edge_mask_regs[4];
 | 
			
		||||
-	u32                level_mask_regs[4];
 | 
			
		||||
-};
 | 
			
		||||
-
 | 
			
		||||
 /*
 | 
			
		||||
  * Functions returning addresses of individual registers for a given
 | 
			
		||||
  * GPIO controller.
 | 
			
		||||
@@ -218,7 +201,7 @@ static int mvebu_gpio_get(struct gpio_ch
 | 
			
		||||
 	return (u >> pin) & 1;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
-static void mvebu_gpio_blink(struct gpio_chip *chip, unsigned pin, int value)
 | 
			
		||||
+void mvebu_gpio_blink(struct gpio_chip *chip, unsigned pin, int value)
 | 
			
		||||
 {
 | 
			
		||||
 	struct mvebu_gpio_chip *mvchip =
 | 
			
		||||
 		container_of(chip, struct mvebu_gpio_chip, chip);
 | 
			
		||||
@@ -607,6 +590,8 @@ static int mvebu_gpio_suspend(struct pla
 | 
			
		||||
 		BUG();
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
+	mvebu_pwm_suspend(mvchip);
 | 
			
		||||
+
 | 
			
		||||
 	return 0;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
@@ -650,6 +635,8 @@ static int mvebu_gpio_resume(struct plat
 | 
			
		||||
 		BUG();
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
+	mvebu_pwm_resume(mvchip);
 | 
			
		||||
+
 | 
			
		||||
 	return 0;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
@@ -661,7 +648,6 @@ static int mvebu_gpio_probe(struct platf
 | 
			
		||||
 	struct resource *res;
 | 
			
		||||
 	struct irq_chip_generic *gc;
 | 
			
		||||
 	struct irq_chip_type *ct;
 | 
			
		||||
-	struct clk *clk;
 | 
			
		||||
 	unsigned int ngpios;
 | 
			
		||||
 	int soc_variant;
 | 
			
		||||
 	int i, cpu, id;
 | 
			
		||||
@@ -691,10 +677,10 @@ static int mvebu_gpio_probe(struct platf
 | 
			
		||||
 		return id;
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
-	clk = devm_clk_get(&pdev->dev, NULL);
 | 
			
		||||
+	mvchip->clk = devm_clk_get(&pdev->dev, NULL);
 | 
			
		||||
 	/* Not all SoCs require a clock.*/
 | 
			
		||||
-	if (!IS_ERR(clk))
 | 
			
		||||
-		clk_prepare_enable(clk);
 | 
			
		||||
+	if (!IS_ERR(mvchip->clk))
 | 
			
		||||
+		clk_prepare_enable(mvchip->clk);
 | 
			
		||||
 
 | 
			
		||||
 	mvchip->soc_variant = soc_variant;
 | 
			
		||||
 	mvchip->chip.label = dev_name(&pdev->dev);
 | 
			
		||||
@@ -828,7 +814,8 @@ static int mvebu_gpio_probe(struct platf
 | 
			
		||||
 		goto err_generic_chip;
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
-	return 0;
 | 
			
		||||
+	/* Armada 370/XP has simple PWM support for gpio lines */
 | 
			
		||||
+	return mvebu_pwm_probe(pdev, mvchip, id);
 | 
			
		||||
 
 | 
			
		||||
 err_generic_chip:
 | 
			
		||||
 	irq_remove_generic_chip(gc, IRQ_MSK(ngpios), IRQ_NOREQUEST,
 | 
			
		||||
--- /dev/null
 | 
			
		||||
+++ b/drivers/gpio/gpio-mvebu.h
 | 
			
		||||
@@ -0,0 +1,79 @@
 | 
			
		||||
+/*
 | 
			
		||||
+ * Interface between MVEBU GPIO driver and PWM driver for GPIO pins
 | 
			
		||||
+ *
 | 
			
		||||
+ * Copyright (C) 2015, Andrew Lunn <andrew@lunn.ch>
 | 
			
		||||
+ *
 | 
			
		||||
+ * 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.
 | 
			
		||||
+ */
 | 
			
		||||
+
 | 
			
		||||
+#ifndef MVEBU_GPIO_PWM_H
 | 
			
		||||
+#define MVEBU_GPIO_PWM_H
 | 
			
		||||
+
 | 
			
		||||
+#define BLINK_ON_DURATION	0x0
 | 
			
		||||
+#define BLINK_OFF_DURATION	0x4
 | 
			
		||||
+#define GPIO_BLINK_CNT_SELECT	0x0020
 | 
			
		||||
+
 | 
			
		||||
+struct mvebu_pwm {
 | 
			
		||||
+	void __iomem	*membase;
 | 
			
		||||
+	unsigned long	 clk_rate;
 | 
			
		||||
+	bool		 used;
 | 
			
		||||
+	unsigned	 pin;
 | 
			
		||||
+	struct pwm_chip	 chip;
 | 
			
		||||
+	int		 id;
 | 
			
		||||
+	spinlock_t	 lock;
 | 
			
		||||
+
 | 
			
		||||
+	/* Used to preserve GPIO/PWM registers across suspend /
 | 
			
		||||
+	 * resume */
 | 
			
		||||
+	u32		 blink_select;
 | 
			
		||||
+	u32		 blink_on_duration;
 | 
			
		||||
+	u32		 blink_off_duration;
 | 
			
		||||
+};
 | 
			
		||||
+
 | 
			
		||||
+struct mvebu_gpio_chip {
 | 
			
		||||
+	struct gpio_chip   chip;
 | 
			
		||||
+	spinlock_t	   lock;
 | 
			
		||||
+	void __iomem	  *membase;
 | 
			
		||||
+	void __iomem	  *percpu_membase;
 | 
			
		||||
+	int		   irqbase;
 | 
			
		||||
+	struct irq_domain *domain;
 | 
			
		||||
+	int		   soc_variant;
 | 
			
		||||
+	struct clk	  *clk;
 | 
			
		||||
+#ifdef CONFIG_PWM
 | 
			
		||||
+	struct mvebu_pwm pwm;
 | 
			
		||||
+#endif
 | 
			
		||||
+	/* Used to preserve GPIO registers across suspend/resume */
 | 
			
		||||
+	u32		   out_reg;
 | 
			
		||||
+	u32		   io_conf_reg;
 | 
			
		||||
+	u32		   blink_en_reg;
 | 
			
		||||
+	u32		   in_pol_reg;
 | 
			
		||||
+	u32		   edge_mask_regs[4];
 | 
			
		||||
+	u32		   level_mask_regs[4];
 | 
			
		||||
+};
 | 
			
		||||
+
 | 
			
		||||
+void mvebu_gpio_blink(struct gpio_chip *chip, unsigned pin, int value);
 | 
			
		||||
+
 | 
			
		||||
+#ifdef CONFIG_PWM
 | 
			
		||||
+int mvebu_pwm_probe(struct platform_device *pdev,
 | 
			
		||||
+		    struct mvebu_gpio_chip *mvchip,
 | 
			
		||||
+		    int id);
 | 
			
		||||
+void mvebu_pwm_suspend(struct mvebu_gpio_chip *mvchip);
 | 
			
		||||
+void mvebu_pwm_resume(struct mvebu_gpio_chip *mvchip);
 | 
			
		||||
+#else
 | 
			
		||||
+int mvebu_pwm_probe(struct platform_device *pdev,
 | 
			
		||||
+		    struct mvebu_gpio_chip *mvchip,
 | 
			
		||||
+		    int id)
 | 
			
		||||
+{
 | 
			
		||||
+	return 0;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+void mvebu_pwm_suspend(struct mvebu_gpio_chip *mvchip)
 | 
			
		||||
+{
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+void mvebu_pwm_resume(struct mvebu_gpio_chip *mvchip)
 | 
			
		||||
+{
 | 
			
		||||
+}
 | 
			
		||||
+#endif
 | 
			
		||||
+#endif
 | 
			
		||||
@@ -0,0 +1,52 @@
 | 
			
		||||
Document the optional parameters needed for PWM operation of gpio
 | 
			
		||||
lines.
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
 | 
			
		||||
---
 | 
			
		||||
 .../devicetree/bindings/gpio/gpio-mvebu.txt        | 31 ++++++++++++++++++++++
 | 
			
		||||
 1 file changed, 31 insertions(+)
 | 
			
		||||
 | 
			
		||||
--- a/Documentation/devicetree/bindings/gpio/gpio-mvebu.txt
 | 
			
		||||
+++ b/Documentation/devicetree/bindings/gpio/gpio-mvebu.txt
 | 
			
		||||
@@ -38,6 +38,23 @@ Required properties:
 | 
			
		||||
 - #gpio-cells: Should be two. The first cell is the pin number. The
 | 
			
		||||
   second cell is reserved for flags, unused at the moment.
 | 
			
		||||
 
 | 
			
		||||
+Optional properties:
 | 
			
		||||
+
 | 
			
		||||
+In order to use the gpio lines in PWM mode, some additional optional
 | 
			
		||||
+properties are required. Only Armada 370 and XP supports these
 | 
			
		||||
+properties.
 | 
			
		||||
+
 | 
			
		||||
+- reg: an additional register set is needed, for the GPIO Blink
 | 
			
		||||
+  Counter on/off registers.
 | 
			
		||||
+
 | 
			
		||||
+- reg-names: Must contain an entry "pwm" corresponding to the
 | 
			
		||||
+  additional register range needed for pwm operation.
 | 
			
		||||
+
 | 
			
		||||
+- #pwm-cells: Should be two. The first cell is the pin number. The
 | 
			
		||||
+  second cell is reserved for flags, unused at the moment.
 | 
			
		||||
+
 | 
			
		||||
+- clocks: Must be a phandle to the clock for the gpio controller.
 | 
			
		||||
+
 | 
			
		||||
 Example:
 | 
			
		||||
 
 | 
			
		||||
 		gpio0: gpio@d0018100 {
 | 
			
		||||
@@ -51,3 +68,17 @@ Example:
 | 
			
		||||
 			#interrupt-cells = <2>;
 | 
			
		||||
 			interrupts = <16>, <17>, <18>, <19>;
 | 
			
		||||
 		};
 | 
			
		||||
+
 | 
			
		||||
+		gpio1: gpio@18140 {
 | 
			
		||||
+			compatible = "marvell,orion-gpio";
 | 
			
		||||
+			reg = <0x18140 0x40>, <0x181c8 0x08>;
 | 
			
		||||
+			reg-names = "gpio", "pwm";
 | 
			
		||||
+			ngpios = <17>;
 | 
			
		||||
+			gpio-controller;
 | 
			
		||||
+			#gpio-cells = <2>;
 | 
			
		||||
+			#pwm-cells = <2>;
 | 
			
		||||
+			interrupt-controller;
 | 
			
		||||
+			#interrupt-cells = <2>;
 | 
			
		||||
+			interrupts = <87>, <88>, <89>;
 | 
			
		||||
+			clocks = <&coreclk 0>;
 | 
			
		||||
+		};
 | 
			
		||||
@@ -0,0 +1,149 @@
 | 
			
		||||
Add properties to the gpio nodes to allow them to be also used
 | 
			
		||||
as pwm lines.
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
 | 
			
		||||
---
 | 
			
		||||
 arch/arm/boot/dts/armada-370.dtsi        | 10 ++++++++--
 | 
			
		||||
 arch/arm/boot/dts/armada-xp-mv78230.dtsi | 10 ++++++++--
 | 
			
		||||
 arch/arm/boot/dts/armada-xp-mv78260.dtsi |  8 ++++++--
 | 
			
		||||
 arch/arm/boot/dts/armada-xp-mv78460.dtsi | 10 ++++++++--
 | 
			
		||||
 4 files changed, 30 insertions(+), 8 deletions(-)
 | 
			
		||||
 | 
			
		||||
--- a/arch/arm/boot/dts/armada-370.dtsi
 | 
			
		||||
+++ b/arch/arm/boot/dts/armada-370.dtsi
 | 
			
		||||
@@ -162,24 +162,30 @@
 | 
			
		||||
 
 | 
			
		||||
 			gpio0: gpio@18100 {
 | 
			
		||||
 				compatible = "marvell,orion-gpio";
 | 
			
		||||
-				reg = <0x18100 0x40>;
 | 
			
		||||
+				reg = <0x18100 0x40>, <0x181c0 0x08>;
 | 
			
		||||
+				reg-names = "gpio", "pwm";
 | 
			
		||||
 				ngpios = <32>;
 | 
			
		||||
 				gpio-controller;
 | 
			
		||||
 				#gpio-cells = <2>;
 | 
			
		||||
+				#pwm-cells = <2>;
 | 
			
		||||
 				interrupt-controller;
 | 
			
		||||
 				#interrupt-cells = <2>;
 | 
			
		||||
 				interrupts = <82>, <83>, <84>, <85>;
 | 
			
		||||
+				clocks = <&coreclk 0>;
 | 
			
		||||
 			};
 | 
			
		||||
 
 | 
			
		||||
 			gpio1: gpio@18140 {
 | 
			
		||||
 				compatible = "marvell,orion-gpio";
 | 
			
		||||
-				reg = <0x18140 0x40>;
 | 
			
		||||
+				reg = <0x18140 0x40>, <0x181c8 0x08>;
 | 
			
		||||
+				reg-names = "gpio", "pwm";
 | 
			
		||||
 				ngpios = <32>;
 | 
			
		||||
 				gpio-controller;
 | 
			
		||||
 				#gpio-cells = <2>;
 | 
			
		||||
+				#pwm-cells = <2>;
 | 
			
		||||
 				interrupt-controller;
 | 
			
		||||
 				#interrupt-cells = <2>;
 | 
			
		||||
 				interrupts = <87>, <88>, <89>, <90>;
 | 
			
		||||
+				clocks = <&coreclk 0>;
 | 
			
		||||
 			};
 | 
			
		||||
 
 | 
			
		||||
 			gpio2: gpio@18180 {
 | 
			
		||||
--- a/arch/arm/boot/dts/armada-xp-mv78230.dtsi
 | 
			
		||||
+++ b/arch/arm/boot/dts/armada-xp-mv78230.dtsi
 | 
			
		||||
@@ -203,24 +203,30 @@
 | 
			
		||||
 		internal-regs {
 | 
			
		||||
 			gpio0: gpio@18100 {
 | 
			
		||||
 				compatible = "marvell,orion-gpio";
 | 
			
		||||
-				reg = <0x18100 0x40>;
 | 
			
		||||
+				reg = <0x18100 0x40>, <0x181c0 0x08>;
 | 
			
		||||
+				reg-names = "gpio", "pwm";
 | 
			
		||||
 				ngpios = <32>;
 | 
			
		||||
 				gpio-controller;
 | 
			
		||||
 				#gpio-cells = <2>;
 | 
			
		||||
+				#pwm-cells = <2>;
 | 
			
		||||
 				interrupt-controller;
 | 
			
		||||
 				#interrupt-cells = <2>;
 | 
			
		||||
 				interrupts = <82>, <83>, <84>, <85>;
 | 
			
		||||
+				clocks = <&coreclk 0>;
 | 
			
		||||
 			};
 | 
			
		||||
 
 | 
			
		||||
 			gpio1: gpio@18140 {
 | 
			
		||||
 				compatible = "marvell,orion-gpio";
 | 
			
		||||
-				reg = <0x18140 0x40>;
 | 
			
		||||
+				reg = <0x18140 0x40>, <0x181c8 0x08>;
 | 
			
		||||
+				reg-names = "gpio", "pwm";
 | 
			
		||||
 				ngpios = <17>;
 | 
			
		||||
 				gpio-controller;
 | 
			
		||||
 				#gpio-cells = <2>;
 | 
			
		||||
+				#pwm-cells = <2>;
 | 
			
		||||
 				interrupt-controller;
 | 
			
		||||
 				#interrupt-cells = <2>;
 | 
			
		||||
 				interrupts = <87>, <88>, <89>;
 | 
			
		||||
+				clocks = <&coreclk 0>;
 | 
			
		||||
 			};
 | 
			
		||||
 		};
 | 
			
		||||
 	};
 | 
			
		||||
--- a/arch/arm/boot/dts/armada-xp-mv78260.dtsi
 | 
			
		||||
+++ b/arch/arm/boot/dts/armada-xp-mv78260.dtsi
 | 
			
		||||
@@ -286,24 +286,28 @@
 | 
			
		||||
 		internal-regs {
 | 
			
		||||
 			gpio0: gpio@18100 {
 | 
			
		||||
 				compatible = "marvell,orion-gpio";
 | 
			
		||||
-				reg = <0x18100 0x40>;
 | 
			
		||||
+				reg = <0x18100 0x40>, <0x181c0 0x08>;
 | 
			
		||||
+				reg-names = "gpio", "pwm";
 | 
			
		||||
 				ngpios = <32>;
 | 
			
		||||
 				gpio-controller;
 | 
			
		||||
 				#gpio-cells = <2>;
 | 
			
		||||
+				#pwm-cells = <2>;
 | 
			
		||||
 				interrupt-controller;
 | 
			
		||||
 				#interrupt-cells = <2>;
 | 
			
		||||
 				interrupts = <82>, <83>, <84>, <85>;
 | 
			
		||||
+				clocks = <&coreclk 0>;
 | 
			
		||||
 			};
 | 
			
		||||
 
 | 
			
		||||
 			gpio1: gpio@18140 {
 | 
			
		||||
 				compatible = "marvell,orion-gpio";
 | 
			
		||||
-				reg = <0x18140 0x40>;
 | 
			
		||||
+				reg = <0x18140 0x40>, <0x181c8 0x08>;
 | 
			
		||||
 				ngpios = <32>;
 | 
			
		||||
 				gpio-controller;
 | 
			
		||||
 				#gpio-cells = <2>;
 | 
			
		||||
 				interrupt-controller;
 | 
			
		||||
 				#interrupt-cells = <2>;
 | 
			
		||||
 				interrupts = <87>, <88>, <89>, <90>;
 | 
			
		||||
+				clocks = <&coreclk 0>;
 | 
			
		||||
 			};
 | 
			
		||||
 
 | 
			
		||||
 			gpio2: gpio@18180 {
 | 
			
		||||
--- a/arch/arm/boot/dts/armada-xp-mv78460.dtsi
 | 
			
		||||
+++ b/arch/arm/boot/dts/armada-xp-mv78460.dtsi
 | 
			
		||||
@@ -324,24 +324,30 @@
 | 
			
		||||
 		internal-regs {
 | 
			
		||||
 			gpio0: gpio@18100 {
 | 
			
		||||
 				compatible = "marvell,orion-gpio";
 | 
			
		||||
-				reg = <0x18100 0x40>;
 | 
			
		||||
+				reg = <0x18100 0x40>, <0x181c0 0x08>;
 | 
			
		||||
+				reg-names = "gpio", "pwm";
 | 
			
		||||
 				ngpios = <32>;
 | 
			
		||||
 				gpio-controller;
 | 
			
		||||
 				#gpio-cells = <2>;
 | 
			
		||||
+				#pwm-cells = <2>;
 | 
			
		||||
 				interrupt-controller;
 | 
			
		||||
 				#interrupt-cells = <2>;
 | 
			
		||||
 				interrupts = <82>, <83>, <84>, <85>;
 | 
			
		||||
+				clocks = <&coreclk 0>;
 | 
			
		||||
 			};
 | 
			
		||||
 
 | 
			
		||||
 			gpio1: gpio@18140 {
 | 
			
		||||
 				compatible = "marvell,orion-gpio";
 | 
			
		||||
-				reg = <0x18140 0x40>;
 | 
			
		||||
+				reg = <0x18140 0x40>, <0x181c8 0x08>;
 | 
			
		||||
+				reg-names = "gpio", "pwm";
 | 
			
		||||
 				ngpios = <32>;
 | 
			
		||||
 				gpio-controller;
 | 
			
		||||
 				#gpio-cells = <2>;
 | 
			
		||||
+				#pwm-cells = <2>;
 | 
			
		||||
 				interrupt-controller;
 | 
			
		||||
 				#interrupt-cells = <2>;
 | 
			
		||||
 				interrupts = <87>, <88>, <89>, <90>;
 | 
			
		||||
+				clocks = <&coreclk 0>;
 | 
			
		||||
 			};
 | 
			
		||||
 
 | 
			
		||||
 			gpio2: gpio@18180 {
 | 
			
		||||
@@ -0,0 +1,18 @@
 | 
			
		||||
Now that the gpio driver also supports PWM operation, enable
 | 
			
		||||
the PWM framework in mvebu_v7_defconfig.
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
 | 
			
		||||
---
 | 
			
		||||
 arch/arm/configs/mvebu_v7_defconfig | 1 +
 | 
			
		||||
 1 file changed, 1 insertion(+)
 | 
			
		||||
 | 
			
		||||
--- a/arch/arm/configs/mvebu_v7_defconfig
 | 
			
		||||
+++ b/arch/arm/configs/mvebu_v7_defconfig
 | 
			
		||||
@@ -131,6 +131,7 @@ CONFIG_DMADEVICES=y
 | 
			
		||||
 CONFIG_MV_XOR=y
 | 
			
		||||
 # CONFIG_IOMMU_SUPPORT is not set
 | 
			
		||||
 CONFIG_MEMORY=y
 | 
			
		||||
+CONFIG_PWM=y
 | 
			
		||||
 CONFIG_EXT4_FS=y
 | 
			
		||||
 CONFIG_ISO9660_FS=y
 | 
			
		||||
 CONFIG_JOLIET=y
 | 
			
		||||
@@ -0,0 +1,28 @@
 | 
			
		||||
The mvebu gpio driver can also perform PWM on some pins. Us the
 | 
			
		||||
pwm-fan driver to control the fan of the WRT1900AC, giving us fine
 | 
			
		||||
grain control over its speed and hence noise.
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
 | 
			
		||||
---
 | 
			
		||||
 arch/arm/boot/dts/armada-xp-wrt1900ac.dts | 8 +++-----
 | 
			
		||||
 1 file changed, 3 insertions(+), 5 deletions(-)
 | 
			
		||||
 | 
			
		||||
--- a/arch/arm/boot/dts/armada-xp-linksys-mamba.dts
 | 
			
		||||
+++ b/arch/arm/boot/dts/armada-xp-linksys-mamba.dts
 | 
			
		||||
@@ -428,13 +428,11 @@
 | 
			
		||||
 		};
 | 
			
		||||
 	};
 | 
			
		||||
 
 | 
			
		||||
-	gpio_fan {
 | 
			
		||||
+	pwm_fan {
 | 
			
		||||
 		/* SUNON HA4010V4-0000-C99 */
 | 
			
		||||
-		compatible = "gpio-fan";
 | 
			
		||||
-		gpios = <&gpio0 24 0>;
 | 
			
		||||
 
 | 
			
		||||
-		gpio-fan,speed-map = <0    0
 | 
			
		||||
-				      4500 1>;
 | 
			
		||||
+		compatible = "pwm-fan";
 | 
			
		||||
+		pwms = <&gpio0 24 4000 0>;
 | 
			
		||||
 	};
 | 
			
		||||
 
 | 
			
		||||
 	dsa@0 {
 | 
			
		||||
@@ -0,0 +1,19 @@
 | 
			
		||||
--- a/arch/arm/boot/dts/armada-388-rd.dts
 | 
			
		||||
+++ b/arch/arm/boot/dts/armada-388-rd.dts
 | 
			
		||||
@@ -79,6 +79,16 @@
 | 
			
		||||
 					compatible = "st,m25p128", "jedec,spi-nor";
 | 
			
		||||
 					reg = <0>; /* Chip select 0 */
 | 
			
		||||
 					spi-max-frequency = <108000000>;
 | 
			
		||||
+
 | 
			
		||||
+					partition@0 {
 | 
			
		||||
+						label = "uboot";
 | 
			
		||||
+						reg = <0 0x400000>;
 | 
			
		||||
+					};
 | 
			
		||||
+
 | 
			
		||||
+					partition@1 {
 | 
			
		||||
+						label = "firmware";
 | 
			
		||||
+						reg = <0x400000 0xc00000>;
 | 
			
		||||
+					};
 | 
			
		||||
 				};
 | 
			
		||||
 			};
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,34 @@
 | 
			
		||||
From 9861f93a59142a3131870df2521eb2deb73026d7 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Maxime Ripard <maxime.ripard@free-electrons.com>
 | 
			
		||||
Date: Tue, 13 Jan 2015 11:14:09 +0100
 | 
			
		||||
Subject: [PATCH 2/2] ARM: mvebu: 385-ap: Add partitions
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
 | 
			
		||||
---
 | 
			
		||||
 arch/arm/boot/dts/armada-385-db-ap.dts | 15 +++++++++++++++
 | 
			
		||||
 1 file changed, 15 insertions(+)
 | 
			
		||||
 | 
			
		||||
--- a/arch/arm/boot/dts/armada-385-db-ap.dts
 | 
			
		||||
+++ b/arch/arm/boot/dts/armada-385-db-ap.dts
 | 
			
		||||
@@ -184,6 +184,21 @@
 | 
			
		||||
 				marvell,nand-keep-config;
 | 
			
		||||
 				marvell,nand-enable-arbiter;
 | 
			
		||||
 				nand-on-flash-bbt;
 | 
			
		||||
+
 | 
			
		||||
+				mtd0@00000000 {
 | 
			
		||||
+					label = "u-boot";
 | 
			
		||||
+					reg = <0x00000000 0x00800000>;
 | 
			
		||||
+				};
 | 
			
		||||
+
 | 
			
		||||
+				mtd1@00800000 {
 | 
			
		||||
+					label = "kernel";
 | 
			
		||||
+					reg = <0x00800000 0x00800000>;
 | 
			
		||||
+				};
 | 
			
		||||
+
 | 
			
		||||
+				mtd2@01000000 {
 | 
			
		||||
+					label = "ubi";
 | 
			
		||||
+					reg = <0x01000000 0x3f000000>;
 | 
			
		||||
+				};
 | 
			
		||||
 			};
 | 
			
		||||
 
 | 
			
		||||
 			usb3@f0000 {
 | 
			
		||||
@@ -0,0 +1,21 @@
 | 
			
		||||
--- a/arch/arm/boot/dts/armada-388-clearfog.dts
 | 
			
		||||
+++ b/arch/arm/boot/dts/armada-388-clearfog.dts
 | 
			
		||||
@@ -430,6 +430,18 @@
 | 
			
		||||
 		};
 | 
			
		||||
 	};
 | 
			
		||||
 
 | 
			
		||||
+	mvsw61xx {
 | 
			
		||||
+		#address-cells = <1>;
 | 
			
		||||
+		#size-cells = <0>;
 | 
			
		||||
+		compatible = "marvell,88e6176";
 | 
			
		||||
+		status = "okay";
 | 
			
		||||
+		reg = <0x4>;
 | 
			
		||||
+		is-indirect;
 | 
			
		||||
+
 | 
			
		||||
+		mii-bus = <&mdio>;
 | 
			
		||||
+		cpu-port-0 = <5>;
 | 
			
		||||
+	};
 | 
			
		||||
+
 | 
			
		||||
 	gpio-keys {
 | 
			
		||||
 		compatible = "gpio-keys";
 | 
			
		||||
 		pinctrl-0 = <&rear_button_pins>;
 | 
			
		||||
@@ -0,0 +1,84 @@
 | 
			
		||||
From 63ff73593c2f5d3fc1cba479321d192caaca48aa Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
Date: Sat, 12 Sep 2015 18:43:39 +0100
 | 
			
		||||
Subject: [PATCH 738/744] ARM: dts: armada388-clearfog: add SFP module support
 | 
			
		||||
 | 
			
		||||
Add SFP module support for Clearfog using the SFP phylink support.
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
 | 
			
		||||
---
 | 
			
		||||
 arch/arm/boot/dts/armada-388-clearfog.dts | 44 ++++++++-----------------------
 | 
			
		||||
 1 file changed, 11 insertions(+), 33 deletions(-)
 | 
			
		||||
 | 
			
		||||
--- a/arch/arm/boot/dts/armada-388-clearfog.dts
 | 
			
		||||
+++ b/arch/arm/boot/dts/armada-388-clearfog.dts
 | 
			
		||||
@@ -90,16 +90,12 @@
 | 
			
		||||
 			};
 | 
			
		||||
 
 | 
			
		||||
 			ethernet@34000 {
 | 
			
		||||
+				managed = "in-band-status";
 | 
			
		||||
 				phy-mode = "sgmii";
 | 
			
		||||
 				buffer-manager = <&bm>;
 | 
			
		||||
 				bm,pool-long = <3>;
 | 
			
		||||
 				bm,pool-short = <1>;
 | 
			
		||||
 				status = "okay";
 | 
			
		||||
-
 | 
			
		||||
-				fixed-link {
 | 
			
		||||
-					speed = <1000>;
 | 
			
		||||
-					full-duplex;
 | 
			
		||||
-				};
 | 
			
		||||
 			};
 | 
			
		||||
 
 | 
			
		||||
 			i2c@11000 {
 | 
			
		||||
@@ -183,34 +179,6 @@
 | 
			
		||||
 						output-low;
 | 
			
		||||
 						line-name = "m.2 devslp";
 | 
			
		||||
 					};
 | 
			
		||||
-					sfp_los {
 | 
			
		||||
-						/* SFP loss of signal */
 | 
			
		||||
-						gpio-hog;
 | 
			
		||||
-						gpios = <12 GPIO_ACTIVE_HIGH>;
 | 
			
		||||
-						input;
 | 
			
		||||
-						line-name = "sfp-los";
 | 
			
		||||
-					};
 | 
			
		||||
-					sfp_tx_fault {
 | 
			
		||||
-						/* SFP laser fault */
 | 
			
		||||
-						gpio-hog;
 | 
			
		||||
-						gpios = <13 GPIO_ACTIVE_HIGH>;
 | 
			
		||||
-						input;
 | 
			
		||||
-						line-name = "sfp-tx-fault";
 | 
			
		||||
-					};
 | 
			
		||||
-					sfp_tx_disable {
 | 
			
		||||
-						/* SFP transmit disable */
 | 
			
		||||
-						gpio-hog;
 | 
			
		||||
-						gpios = <14 GPIO_ACTIVE_HIGH>;
 | 
			
		||||
-						output-low;
 | 
			
		||||
-						line-name = "sfp-tx-disable";
 | 
			
		||||
-					};
 | 
			
		||||
-					sfp_mod_def0 {
 | 
			
		||||
-						/* SFP module present */
 | 
			
		||||
-						gpio-hog;
 | 
			
		||||
-						gpios = <15 GPIO_ACTIVE_LOW>;
 | 
			
		||||
-						input;
 | 
			
		||||
-						line-name = "sfp-mod-def0";
 | 
			
		||||
-					};
 | 
			
		||||
 				};
 | 
			
		||||
 
 | 
			
		||||
 				/* The MCP3021 is 100kHz clock only */
 | 
			
		||||
@@ -374,6 +342,16 @@
 | 
			
		||||
 		};
 | 
			
		||||
 	};
 | 
			
		||||
 
 | 
			
		||||
+	sfp: sfp {
 | 
			
		||||
+		compatible = "sff,sfp";
 | 
			
		||||
+		i2c-bus = <&i2c1>;
 | 
			
		||||
+		los-gpio = <&expander0 12 GPIO_ACTIVE_HIGH>;
 | 
			
		||||
+		moddef0-gpio = <&expander0 15 GPIO_ACTIVE_LOW>;
 | 
			
		||||
+		sfp,ethernet = <ð2>;
 | 
			
		||||
+		tx-disable-gpio = <&expander0 14 GPIO_ACTIVE_HIGH>;
 | 
			
		||||
+		tx-fault-gpio = <&expander0 13 GPIO_ACTIVE_HIGH>;
 | 
			
		||||
+	};
 | 
			
		||||
+
 | 
			
		||||
 	dsa@0 {
 | 
			
		||||
 		compatible = "marvell,dsa";
 | 
			
		||||
 		dsa,ethernet = <ð1>;
 | 
			
		||||
							
								
								
									
										96
									
								
								target/linux/mvebu/patches-4.4/300-reprobe_sfp_phy.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								target/linux/mvebu/patches-4.4/300-reprobe_sfp_phy.patch
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,96 @@
 | 
			
		||||
From 28baa5e2635285b178326b301f534ed95c65dd01 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Jonas Gorski <jonas.gorski@gmail.com>
 | 
			
		||||
Date: Thu, 29 Sep 2016 11:44:39 +0200
 | 
			
		||||
Subject: [PATCH] sfp: retry phy probe if unsuccessful
 | 
			
		||||
 | 
			
		||||
Some phys seem to take longer than 50 ms to come out of reset, so retry
 | 
			
		||||
until we find a phy.
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Jonas Gorski <jonas.gorski@gmail.com>
 | 
			
		||||
---
 | 
			
		||||
 drivers/net/phy/sfp.c | 38 +++++++++++++++++++++++++-------------
 | 
			
		||||
 1 file changed, 25 insertions(+), 13 deletions(-)
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/phy/sfp.c
 | 
			
		||||
+++ b/drivers/net/phy/sfp.c
 | 
			
		||||
@@ -488,7 +488,7 @@ static void sfp_sm_phy_detach(struct sfp
 | 
			
		||||
 	sfp->mod_phy = NULL;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
-static void sfp_sm_probe_phy(struct sfp *sfp)
 | 
			
		||||
+static int sfp_sm_probe_phy(struct sfp *sfp)
 | 
			
		||||
 {
 | 
			
		||||
 	struct phy_device *phy;
 | 
			
		||||
 	int err;
 | 
			
		||||
@@ -498,11 +498,11 @@ static void sfp_sm_probe_phy(struct sfp
 | 
			
		||||
 	phy = mdiobus_scan(sfp->i2c_mii, SFP_PHY_ADDR);
 | 
			
		||||
 	if (IS_ERR(phy)) {
 | 
			
		||||
 		dev_err(sfp->dev, "mdiobus scan returned %ld\n", PTR_ERR(phy));
 | 
			
		||||
-		return;
 | 
			
		||||
+		return PTR_ERR(phy);
 | 
			
		||||
 	}
 | 
			
		||||
 	if (!phy) {
 | 
			
		||||
-		dev_info(sfp->dev, "no PHY detected\n");
 | 
			
		||||
-		return;
 | 
			
		||||
+		dev_dbg(sfp->dev, "no PHY detected\n");
 | 
			
		||||
+		return -EAGAIN;
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
 	err = phylink_connect_phy(sfp->phylink, phy);
 | 
			
		||||
@@ -510,11 +510,13 @@ static void sfp_sm_probe_phy(struct sfp
 | 
			
		||||
 		phy_device_remove(phy);
 | 
			
		||||
 		phy_device_free(phy);
 | 
			
		||||
 		dev_err(sfp->dev, "phylink_connect_phy failed: %d\n", err);
 | 
			
		||||
-		return;
 | 
			
		||||
+		return err;
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
 	sfp->mod_phy = phy;
 | 
			
		||||
 	phy_start(phy);
 | 
			
		||||
+
 | 
			
		||||
+	return 0;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
 static void sfp_sm_link_up(struct sfp *sfp)
 | 
			
		||||
@@ -565,13 +567,6 @@ static void sfp_sm_mod_init(struct sfp *
 | 
			
		||||
 {
 | 
			
		||||
 	sfp_module_tx_enable(sfp);
 | 
			
		||||
 
 | 
			
		||||
-	/* Wait t_init before indicating that the link is up, provided the
 | 
			
		||||
-	 * current state indicates no TX_FAULT.  If TX_FAULT clears before
 | 
			
		||||
-	 * this time, that's fine too.
 | 
			
		||||
-	 */
 | 
			
		||||
-	sfp_sm_next(sfp, SFP_S_INIT, T_INIT_JIFFIES);
 | 
			
		||||
-	sfp->sm_retries = 5;
 | 
			
		||||
-
 | 
			
		||||
 	if (sfp->phylink) {
 | 
			
		||||
 		/* Setting the serdes link mode is guesswork: there's no
 | 
			
		||||
 		 * field in the EEPROM which indicates what mode should
 | 
			
		||||
@@ -587,9 +582,26 @@ static void sfp_sm_mod_init(struct sfp *
 | 
			
		||||
 		    !sfp->id.base.e100_base_fx) {
 | 
			
		||||
 			phylink_set_link_an_mode(sfp->phylink, MLO_AN_8023Z);
 | 
			
		||||
 		} else {
 | 
			
		||||
+			int ret;
 | 
			
		||||
+
 | 
			
		||||
 			phylink_set_link_an_mode(sfp->phylink, MLO_AN_SGMII);
 | 
			
		||||
-			sfp_sm_probe_phy(sfp);
 | 
			
		||||
+
 | 
			
		||||
+			ret = sfp_sm_probe_phy(sfp);
 | 
			
		||||
+			if (ret) {
 | 
			
		||||
+				if (ret == -EAGAIN)
 | 
			
		||||
+					sfp_sm_set_timer(sfp, T_PROBE_RETRY);
 | 
			
		||||
+				else
 | 
			
		||||
+					sfp_sm_next(sfp, SFP_S_TX_DISABLE, 0);
 | 
			
		||||
+				return;
 | 
			
		||||
+			}
 | 
			
		||||
 		}
 | 
			
		||||
+
 | 
			
		||||
+		/* Wait t_init before indicating that the link is up, provided the
 | 
			
		||||
+		 * current state indicates no TX_FAULT.  If TX_FAULT clears before
 | 
			
		||||
+		 * this time, that's fine too.
 | 
			
		||||
+		 */
 | 
			
		||||
+		sfp_sm_next(sfp, SFP_S_INIT, T_INIT_JIFFIES);
 | 
			
		||||
+		sfp->sm_retries = 5;
 | 
			
		||||
 	}
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,36 @@
 | 
			
		||||
The hardware queue scheduling is apparently configured with fixed
 | 
			
		||||
priorities, which creates a nasty fairness issue where traffic from one
 | 
			
		||||
CPU can starve traffic from all other CPUs.
 | 
			
		||||
 | 
			
		||||
Work around this issue by forcing all tx packets to go through one CPU,
 | 
			
		||||
until this issue is fixed properly.
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
 | 
			
		||||
---
 | 
			
		||||
--- a/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
+++ b/drivers/net/ethernet/marvell/mvneta.c
 | 
			
		||||
@@ -3984,6 +3984,16 @@ static int mvneta_ethtool_set_eee(struct
 | 
			
		||||
 	return phylink_ethtool_set_eee(pp->phylink, eee);
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
+static u16 mvneta_select_queue(struct net_device *dev, struct sk_buff *skb,
 | 
			
		||||
+			       void *accel_priv,
 | 
			
		||||
+			       select_queue_fallback_t fallback)
 | 
			
		||||
+{
 | 
			
		||||
+	/* XXX: hardware queue scheduling is broken,
 | 
			
		||||
+	 * use only one queue until it is fixed */
 | 
			
		||||
+	return 0;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+
 | 
			
		||||
 static const struct net_device_ops mvneta_netdev_ops = {
 | 
			
		||||
 	.ndo_open            = mvneta_open,
 | 
			
		||||
 	.ndo_stop            = mvneta_stop,
 | 
			
		||||
@@ -3994,6 +4004,7 @@ static const struct net_device_ops mvnet
 | 
			
		||||
 	.ndo_fix_features    = mvneta_fix_features,
 | 
			
		||||
 	.ndo_get_stats64     = mvneta_get_stats64,
 | 
			
		||||
 	.ndo_do_ioctl        = mvneta_ioctl,
 | 
			
		||||
+	.ndo_select_queue    = mvneta_select_queue,
 | 
			
		||||
 };
 | 
			
		||||
 
 | 
			
		||||
 const struct ethtool_ops mvneta_eth_tool_ops = {
 | 
			
		||||
		Reference in New Issue
	
	Block a user